The short answer is:
template<class Sig>
using Result_of = typename std::result_of<Sig>::type;
will make your use cases "work". Some will fail to compile because you passed in the wrong signature, or the types don't match.
However it isn't the best way to do it.
C++11 compilers do not all implement the best-practices version of result_of
: namely, a SFINAE friendly one. If you are writing a helper, I do it in best-practices style.
First, an alias to do decltype
evaluation:
template<class F, class...Args>
using invoke_result = decltype( std::declval<F>()(std::declval<Args>()...));
Next, some metaprogramming boilerplate I find useful:
namespace details {
template<class...>struct voider{using type=void;};
template<class...Ts>using void_t=typename voider<Ts...>::type;
template<template<class...>class Z, class, class...Ts>
struct can_apply:std::false_type{};
template<template<class...>class Z, class...Ts>
struct can_apply<Z, void_t<Z<Ts...>>, Ts...>:std::true_type{};
}
template<template<class...>class Z, class...Ts>
using can_apply=details::can_apply<Z,void,Ts...>;
can_apply< template, args... >
answers the question "is applying the args... to the template valid?". This is surprisingly useful.
As we are in C++11 land, an enable_if_t
alias makes code look prettier:
template<bool b, class T=void>
using enable_if_t=typename std::enable_if<b,T>::type;
We can now start working on a result_of_t
alias:
namespace details {
template<class Sig,class=void>
struct result_of {};
template<class F, class...Args>
struct result_of<
F(Args...),
enable_if_t<can_apply<invoke_result, F, Args...>>
> {
using type=invoke_result<F,Args...>;
};
}
template<class Sig>
using result_of_t = typename details::result_of<Sig>::type;
and we are done.
This generates a SFINAE friendly type alias called result_of_t
that works like a high quality C++14 std::result_of_t
in any compliant C++11 compiler. It won't work well on MSVC, but that is because MSVC2015 still doesn't implement C++11 sufficiently.
All of your examples should work with the above result_of_t
replacing Result_of
, or fail because they are invalid.
int ff(int){return 2;}
typedef bool(*PF)(int);
auto fx = [](char ch){return tolower(ch);};
result_of_t<decltype(&ff)()> r1 = 7;
this fails, because you have to pass an int
to ff
. This would work:
result_of_t<decltype(&ff)(int)> r1 = 7;
result_of_t<PF(int)> r2 = 2;
this assigns 2
to a bool
. So it ... works.
result_of_t<decltype(fx)(char)> r5 = "a";
this assigns "a"
to an int
, which is probably not what you want. (tolower
returns an int
in C/C++).
We can fix this via:
auto fx = [](char ch)->char{return tolower(ch);};
result_of_t<decltype(fx)(char)> r5 = 'a';