As I know, a possible implementation of std::result_of is
template<class F, class... ArgTypes>
struct result_of<F(ArgTypes...)>
{
typedef decltype(
std::declval<F>()(std::declval<ArgTypes>()...)
) type;
};
But when I use std::result_of I have some trouble.
int f(int x)
{
return 0;
}
template<typename T>
void Test(const T& t)
{
decltype(std::declval<T>()(std::declval<int>())) i1 = 1; // ok
typename std::result_of<T(int)>::type i2 = 2; // compile error:
// function returning a function
// I think this means the same thing just as above, right?
}
int main()
{
Test(f);
return 0;
}
What are the differences between these two forms?
std::result_of is declared in C++11 [meta.trans.other] Table 57 as:
template <class Fn, class... ArgTypes> struct result_of<Fn(ArgTypes...)>;
and it requires that:
Fnshall be a callable type (20.8.1), reference to function, or reference to callable type. The expressiondecltype(INVOKE(declval<Fn>(), declval<ArgTypes>()...))shall be well formed.
callable type is defined in [func.def]/3:
A callable type is a function object type (20.8) or a pointer to member.
function object type is defined in [function.objects]/1:
A function object type is an object type (3.9) that can be the type of the postfix-expression in a function call (5.2.2, 13.3.1.1). ...
In your program, f is a reference to a function of type int(int), so T is deduced to the function type int(int). Note that a function type is not one of the valid options for the type Fn to be passed to std::result_type. A reference to function is an acceptable type, however: you should pass the full type of Tests parameter to result_of instead of only T (Demo at Coliru):
template<typename T>
void Test(const T&)
{
decltype(std::declval<T>()(std::declval<int>())) i1 = 1;
typename std::result_of<const T& (int)>::type i2 = 2;
}
Regarding the difference between the two forms, remember that std::declval always returns a reference type; specifically std::declval<T>() returns T&&. So
decltype(std::declval<T>()(std::declval<int>()))
is asking for the what type is returned when a T&& is invoked with an int&& argument.
[basic.compound] describes what function types look like in C++:
— functions, which have parameters of given types and return
voidor references or objects of a given type
Therefore, the return type part of a function type must not itself be a function type, and thus T(int) is not a valid type in the C++ type system when T = int(int).
Moreover, [dcl.fct]/8 clarifies:
Functions shall not have a return type of type array or function
Note also that the actual analogue of your i1 line is typename std::result_of<T>::type i2.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With