33

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.
msc
  • 33,420
  • 29
  • 119
  • 214

4 Answers4

12

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.

Davis Herring
  • 36,443
  • 4
  • 48
  • 76
  • 1
    That page doesn't at all explain how to use `std::invoke_result` or `std::invoke_result_t`, only the deprecated `std::result_of` – haelix Jan 07 '19 at 10:55
  • 2
    @haelix: Add an example there if you think it’s needed. I didn’t write that page, and explaining its use is not particularly relevant to this question. – Davis Herring Jan 07 '19 at 14:33
9

@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, "");
    }

}
Pascal T.
  • 3,866
  • 4
  • 33
  • 36
7

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...>
particle
  • 3,280
  • 4
  • 27
  • 39
3

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.
user541686
  • 205,094
  • 128
  • 528
  • 886