The member is closed, although I do not access it from the outside when the return type is used

How can I fix the following problem?

I am writing some kind of functional library that defines the following functions related to this issue:

  • call(f,arg) : calls a function with an argument. I need only a shell for some situations.
  • comp(f1,f2) : Returns a composition of two functions. Returns an auxiliary functor representing the composition of two functions.

The implementation is as follows (simplified versions that still demonstrate the problem):

 // Call f with one argument template <class Fn, class Arg> auto call(const Fn &f, const Arg & arg) -> decltype(f(arg)) { return f(arg); } // Helper functor for the function below template<class Fn1, class Fn2> class CompFn { Fn1 a; Fn2 b; public: CompFn(const Fn1 &f1, const Fn2 &f2) : a(f1), b(f2) {} template<class Arg> inline auto operator()(const Arg & arg) const -> decltype(call(b, call(a, arg))) { return call(b, call(a, arg)); } }; /** Composition of f1 and f2 (f2 after f1). */ template<class Fn1, class Fn2> CompFn<Fn1,Fn2> comp(const Fn1 &f1, const Fn2 &f2) { return CompFn<Fn1,Fn2>(f1, f2); } 

The following code is used as a simple test:

 // Example: Take the length of the string and compare it against zero. std::function<int(std::string)> stringLength = [](std::string s) { return s.size(); }; std::function<bool(int)> greaterZero = [](int x) { return x > 0; }; auto stringNotEmpty = comp(stringLength, greaterZero); std::string testInput1 = "foo"; std::string testInput2 = ""; 

So far, everything is working fine. Calling comp alone is not a problem. Calling the resulting function directly is also ok. But invoking a composition through call introduces an infinite number of compilation errors (yaaay, new entry!):

 assert(call(stringNotEmpty,testInput1) == true); // line 44 assert(call(stringNotEmpty,testInput2) == false); 

Compilation output (gcc 4.7, full output, see links below):

 prog.cpp:16:9: error: 'std::function<bool(int)> CompFn<std::function<int(std::basic_string<char>)>, std::function<bool(int)> >::b' is private prog.cpp:44:5: error: within this context prog.cpp:15:9: error: 'std::function<int(std::basic_string<char>)> CompFn<std::function<int(std::basic_string<char>)>, std::function<bool(int)> >::a' is private prog.cpp:44:5: error: within this context prog.cpp:22:10: error: template instantiation depth exceeds maximum of 900 (use -ftemplate-depth= to increase the maximum) substituting 'template<class Fn, class Arg> decltype (f(arg)) call(const Fn&, const Arg&) [with Fn = std::function<int(std::basic_string<char>)>; Arg = std::basic_string<char>]' prog.cpp:22:10: required by substitution of 'template<class Arg> decltype (call(((const CompFn*)this)->CompFn<Fn1, Fn2>::b, call(((const CompFn*)this)->CompFn<Fn1, Fn2>::a, arg))) CompFn::operator()(const Arg&) const [with Arg = Arg; Fn1 = std::function<int(std::basic_string<char>)>; Fn2 = std::function<bool(int)>] [with Arg = std::basic_string<char>]' prog.cpp:8:6: required by substitution of 'template<class Fn, class Arg> decltype (f(arg)) call(const Fn&, const Arg&) [with Fn = std::function<int(std::basic_string<char>)>; Arg = std::basic_string<char>]' prog.cpp:22:10: required by substitution of 'template<class Arg> decltype (call(((const CompFn*)this)->CompFn<Fn1, Fn2>::b, call(((const CompFn*)this)->CompFn<Fn1, Fn2>::a, arg))) CompFn::operator()(const Arg&) const [with Arg = Arg; Fn1 = std::function<int(std::basic_string<char>)>; Fn2 = std::function<bool(int)>] [with Arg = std::basic_string<char>]' prog.cpp:8:6: required by substitution of 'template<class Fn, class Arg> decltype (f(arg)) call(const Fn&, const Arg&) [with Fn = std::function<int(std::basic_string<char>)>; Arg = std::basic_string<char>]' prog.cpp:22:10: required by substitution of 'template<class Arg> decltype (call(((const CompFn*)this)->CompFn<Fn1, Fn2>::b, call(((const CompFn*)this)->CompFn<Fn1, Fn2>::a, arg))) CompFn::operator()(const Arg&) const [with Arg = Arg; Fn1 = std::function<int(std::basic_string<char>)>; Fn2 = std::function<bool(int)>] [with Arg = std::basic_string<char>]' prog.cpp:8:6: [ skipping 890 instantiation contexts ] [ ...continues endlessly... ] 

When converting a composition to std::function it also works great. But this will not allow the use of polymorphic functors with my comp function, at least I do not see the option.

One โ€œfixโ€ means not to use the return type trailing type with decltype for Comp::operator() , but it will fix the return type bool (specialized for this scenario).

All four test cases mentioned are summarized:

  • Test1 - Call a song directly โ†’ OK
  • Test2 - Call a song using call Error
  • Test3 - compose in std :: function, then call with call OK
  • Test4 - Call a song using call . Fixed return type Comp::operator() - bool -> OK

My goal is to make call โ€œtastelessโ€ shell for calling any type of function: functors, function pointers, member function pointers, member variable pointers, etc., as well as composition using comp . I have a bunch of overloads for them, but I don't want to introduce overloads for Comp<Fn1,Fn2> , since Fn1 or Fn2 can again be any type of function, this seems to be a "recursive problem".

+8
c ++ c ++ 11 functional-programming templates metaprogramming
source share
2 answers

Try substituting the expression Fn1 for a, Fn2 for b, so as not to mention private terms. I tried this in VC ++, but got another error:

 template<class Arg> inline auto operator()(const Arg & arg) const -> decltype(call(Fn1(), call(Fn2(), arg))) { return call(b, call(a, arg)); } 
+2
source share

Clang compiles your failed test case just fine, and I don't see any error with it, so I think it is a GCC error. Please write a bug report with minimal playback (without inclusion) if you can.

Note. For call , the standard already has something like this - INVOKE , which is not a macro, but is, so to speak, a concept. It is used by std::bind , std::function and other things, one of which is std::reference_wrapper . This means that you can do std::ref(fun)(args...) to achieve the same value as call .

+6
source share

All Articles