What is the reason for `std::result_of` deprecated in C++17?

9.5k Views Asked by At

I saw std::result_of is being deprecated in C++17.

  • What is the reason for std::result_of deprecated in C++17?
  • Also I would like to know the difference between std::result_of and std::invoke_result.
4

There are 4 best solutions below

2
On

T.C. already provided the obvious link, but perhaps the most horrific reason bears repeating: result_of involved forming the type F(Arg1, Arg2, ...) not for a function of those types returning F but for a function of type F accepting those types. (After all, the return type is the result of, well, result_of, not the input!)

Aside from the adjustments associated with forming the function type, the only difference between the two is syntactic.

0
On

@haelix:

I'm totaly with you concerning the lack of example on the cppreference page. Here's my take:

auto add_auto_fn(int a, int b) {
    return a + b;
}

template<typename U, typename V>
auto add_auto_template_fn(U a, V b) {
    return a + b;
}

int fortytwo(int a, int b) { return a + 42; }

struct my_functor{
    auto operator() (int a) { return a + 42; }
};

void test_invoke_result()
{
    {
        // For functions and auto function: use < decltype(&f), Args... >
        using T = std::invoke_result< decltype(&fortytwo), int, int>::type;
        static_assert(std::is_same<T, int>::value, "");
    }
    {
        // For templated auto functions: use < decltype(&f)<Args...>, Args... >
        using T = std::invoke_result< decltype(&add_auto_template_fn<int, double>), int, double>::type;
        static_assert(std::is_same<T, double>::value, "");
    }
    {
        // For simple lambdas: use < decltype(lambda), Args... >
        auto simple_lambda = [](int a) {  return a + 42; };
        using T = std::invoke_result< decltype(simple_lambda), int>::type;
        static_assert(std::is_same<T, int>::value, "");
    }
    {
        // For generic lambdas: use < decltype(lambda), Args... >
        auto generic_lambda = [](auto a) {  return a + 42; };
        using T = std::invoke_result< decltype(generic_lambda), double>::type;
        static_assert(std::is_same<T, double>::value, "");
    }
    {
        // For functors: use < functor, Args... >
        using T = std::invoke_result< my_functor, int>::type;
        static_assert(std::is_same<T, int>::value, "");
    }

}

void test_result_of()
{
    {
        // For functions and auto function: use < decltype(&f)(Args...) >
        using T = std::result_of< decltype(&fortytwo)(int, int)>::type;
        static_assert(std::is_same<T, int>::value, "");
    }
    {
        // For templated auto functions: use < decltype(&f<Args...>)(Args...) >
        using T = std::result_of< decltype(&add_auto_template_fn<int, double>)(int, double)>::type;
        static_assert(std::is_same<T, double>::value, "");
    }
    {
        // For simple lambdas: use < decltype(lambda)(Args...) >
        auto simple_lambda = [](int a) {  return a + 42; };
        using T = std::result_of< decltype(simple_lambda)(int)>::type;
        static_assert(std::is_same<T, int>::value, "");
    }
    {
        // For generic lambdas: use < decltype(lambda)(Args...) >
        auto generic_lambda = [](auto a) {  return a + 42; };
        using T = std::result_of< decltype(generic_lambda)(double)>::type;
        static_assert(std::is_same<T, double>::value, "");
    }
    {
        // For functors: use < functor(Args...) >
        using T = std::result_of< my_functor(int)>::type;
        static_assert(std::is_same<T, int>::value, "");
    }

}
0
On

To use it you have to change from

std::result_of_t<A(B)> 

to

std::invoke_result_t<A, B>

or in template

std::result_of_t<F(Args...)>

to

std::invoke_result_t<F,Args...>
0
On

This is very well-explained on cppreference:

F(Args...) is a function type with Args... being the argument types and F being the return type.
As such, std::result_of suffers from several quirks that led to its deprecation in favor of std::invoke_result in C++17:

  • F cannot be a function type or an array type (but can be a reference to them);
  • if any of the Args has type "array of T" or a function type T, it is automatically adjusted to T*;
  • neither F nor any of Args... can be an abstract class type;
  • if any of Args... has a top-level cv-qualifier, it is discarded;
  • none of Args... may be of type void.