Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

about std::result_of in c++11

Tags:

c++

c++11

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?

like image 972
Leonhart Squall Avatar asked Feb 03 '26 05:02

Leonhart Squall


2 Answers

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:

Fn shall be a callable type (20.8.1), reference to function, or reference to callable type. The expression

decltype(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.

like image 150
Casey Avatar answered Feb 04 '26 17:02

Casey


[basic.compound] describes what function types look like in C++:

functions, which have parameters of given types and return void or 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.

like image 38
Kerrek SB Avatar answered Feb 04 '26 19:02

Kerrek SB