petersohn
petersohn

Reputation: 11724

Compile error when trying to use std::result_of

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

Answers (1)

Kerrek SB
Kerrek SB

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

Related Questions