Templates in C++ allows us to write generic concurrent programs. It is not unusual to have a template argument which represent a function. For example

template <typename Fun>
void function(Fun f, ...)

the function’s argument is a function f of type Fun.

If we use functions as template arguments, then we don’t know what is the return type of the function. (For example, we don’t know the return type of f.) There are some cases, when we would need to know the return type of a function. For example, making a future with std::async requires such knowledge.

Fortunately there exist a solution for this problem. The solution is std::result_of. This class can figure out what is the return type of the function at the compile time.

std::result_of

Let’s look at an example

template <typename Fun, typename... Args>
void checkType(Fun f, Args... args)
{
    using return_t = typename std::result_of< Fun(Args...) >::type;

    std::cout << "int:    " << std::is_same<int, return_t>::value << "\n";
    std::cout << "double: " << std::is_same<double, return_t>::value << "\n";
    std::cout << "float:  " << std::is_same<float, return_t>::value << "\n";
    std::cout << std::endl;
}

The checkType accepts two arguments. First one is a function f of type Fun and the second one represents variadic number of arguments. The assumption is that args are the arguments of f. If you are not familiar with functions, which have variadic number of arguments, look at Variadic number of arguments.

The next line

using return_t = typename std::result_of< Fun(Args...) >::type;

determines the return type of f. This is done with std::result_of. The template parameter of std::result_of must be a signature of a function. Then, the std::result_of< >::type represents the return type of the function, which is determined by the signature. The deduced return type is stored in return_t.

In the next lines, the program prints information about return_t. The statement

std::is_same<T, U>::value

is equal to true if T and U are the same type. Otherwise, the statement is false.

Using std::is_same< >, the program checks if the return_t is equal to int or double or float.

Examples

Let’s look at the behavior of the function checkType.

int fun1(int i)
{
    return i;
}

double fun2(double d)
{
    return d;
}

float fun3(int i1, int i2)
{
    return static_cast<float>(i1 + i2);
}

int main()
{
    int i = 1;
    double d = 1.0;

    std::cout << "Function1: " << std::endl;
    checkType(fun1, i);

    std::cout << "Function2: " << std::endl;
    checkType(fun2, d);

    std::cout << "Function3: " << std::endl;
    checkType(fun3, i, i);
}

We have three functions fun1, fun2 and fun3, which return int, double and float, respectively. In main function, checkType prints information about the return types of fun1, fun2 and fun3 using std::result_of< >.

The output of the program is:

Function1: 
int:    1
double: 0
float:  0

Function2: 
int:    0
double: 1
float:  0

Function3: 
int:    0
double: 0
float:  1

Summary

We learned how to deduce the return type of a function with std::result_of<>.

Links: