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
andstd::invoke_result
.
I saw std::result_of
is being deprecated in C++17.
std::result_of
deprecated in C++17?std::result_of
and std::invoke_result
.@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, "");
}
}
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...>
This is very well-explained on cppreference:
F(Args...)
is a function type withArgs...
being the argument types andF
being the return type.
As such,std::result_of
suffers from several quirks that led to its deprecation in favor ofstd::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 ofT
" or a function typeT
, it is automatically adjusted toT*
;- neither
F
nor any ofArgs...
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 typevoid
.
T.C. already provided the obvious link, but perhaps the most horrific reason bears repeating:
result_of
involved forming the typeF(Arg1, Arg2, ...)
not for a function of those types returningF
but for a function of typeF
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.