Reputation: 11724
I want to deduce the return type of a function coming as a template parameter. Consider the following code:
#include <type_traits>
struct Result {};
Result foo() { return Result{}; }
template<typename Factory>
void check(Factory) {
using ActualResult = typename std::result_of<Factory()>::type;
static_assert(std::is_same<Result, ActualResult>::value, "");
}
int main() {
check(foo);
}
This works as expected. However, if I change the parameter of check()
to const Factory&
, then it does not compile. The error from gcc is:
prog.cc: In instantiation of 'void check(const Factory&) [with Factory = Result()]':
prog.cc:14:14: required from here
prog.cc:9:66: error: function returning a function
using ActualResult = typename std::result_of<Factory()>::type;
^
prog.cc:10:65: error: function returning a function
static_assert(std::is_same<Result, ActualResult>::value, "");
^
What's the problem here? How can I make it work?
Upvotes: 2
Views: 100
Reputation: 476940
Functions (just like arrays) can neither be passed as prvalue arguments or returned as prvalues.
Therefore, template <typename Factory> void check(Factory)
, which takes a prvalue argument, will cause foo
to decay to the function pointer, and check(foo)
will cause Factory
to be deduced as Result (*)()
. Finally, result_of<Factory()>
gives the result of calling the callable type that is the function pointer with no arguments.
When you change check
to check(const Factory&)
, the function takes an lvalue, and so there is no decay, and Factory
is deduced as the function type Result()
. This is not a type that you are allowed to pass to result_of
*, which requires either a callable type or a reference to a function. That is, you should use result_of<Factory&()>
in that case.
*) In C++11. The rules for result_of
may have been relaxed in later revisions, and C++17 deprecates result_of
.
Upvotes: 2