您无需将std::remove_reference 或std::decay 转换应用于推导的Function 类型,以便与std::result_of 一起使用。您需要的是类似于 函数调用表达式的正确语法:
#include <type_traits>
#include <utility>
template <typename Function>
auto call_function(Function&& f)
-> typename std::result_of<Function()>::type
// ~^
{
return std::forward<Function>(f)();
}
template <typename Function, typename Class>
auto call_member_function(Function&& f, Class* instance)
-> typename std::result_of<Function(Class*)>::type
// ~~~~~~~^
{
return (instance->*std::forward<Function>(f))();
}
DEMO
如何使这个函数适用于具有不同数量参数的函数?
#include <type_traits>
#include <utility>
template <typename Function, typename... Args>
auto call_function(Function&& f, Args&&... args)
-> typename std::result_of<Function(Args...)>::type
{
return std::forward<Function>(f)(std::forward<Args>(args)...);
}
template <typename Function, typename Class, typename... Args>
auto call_member_function(Function&& f, Class* instance, Args&&... args)
-> typename std::result_of<Function(Class*, Args...)>::type
{
return (instance->*std::forward<Function>(f))(std::forward<Args>(args)...);
}
DEMO 2
参数列表 (Args...) 应该已经是 Function 的一部分,为什么我又需要它们?或者更确切地说,有没有办法让 std::result_of 在没有它们的情况下工作?
是的,参数列表已经是推断出的Function 签名的一部分。诀窍是,std::result_of<F> 不是这样工作的——它只使用函数声明的语法。
std::result_of<F> 用于在使用给定类型的参数调用时查询给定函子对象的结果类型。
函数的结果类型通常是什么,例如 int 对应于 int(char,float),在 std::result_of 内,它被视为函数调用运算符将使用的函子对象的类型被应用于。因此,当您将Function 定义如下时:
using Function = int(char,float);
那么std::result_of<Function>::type 等于:
std::result_of<int(char,float)>::type
// | | |
// | | `~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~.
// | `~~~~~~~~~~~~~~~~~~~~~~~~~. |
// `~~~~~~~~. | |
// V V V
decltype( std::declval<int>() ( std::declval<char>(), std::declval<float>() ) )
// ^ ^ ^~~~~~~~~~~~~~~^
// instance of a functor call operator arguments
即,在std::result_of的部分特化中推导出的结果类型用于获取函子对象的实例。由于没有定义int 的函数调用运算符,因此上述尝试编译失败。
如果Function 被推断为对函数的引用,那么您最终会得到一个不完整的std::result_of 主模板,因为它甚至不匹配它的任何部分特化。
如果你想得到一个函数的返回类型(不先提供参数,所以decltype()不是一个选项),你可以在函数模板参数推导时进行推导:
template <typename R, typename... Params, typename... Args>
R call_function(R(*f)(Params...), Args&&... args)
{
return f(std::forward<Args>(args)...);
}
template <typename R, typename Class, typename... Params, typename... Args>
R call_member_function(R(Class::*f)(Params...), Class* instance, Args&&... args)
{
return (instance->*f)(std::forward<Args>(args)...);
}
或通过提供单独的特征类:
#include <utility>
#include <type_traits>
template <typename F>
struct return_type;
template <typename R, typename... Args>
struct return_type<R(Args...)> { using type = R; };
template <typename R, typename... Args>
struct return_type<R(*)(Args...)> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type<R(C::*)(Args...)> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type<R(C::*)(Args...) &> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type<R(C::*)(Args...) &&> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type<R(C::*)(Args...) const> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type<R(C::*)(Args...) const&> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type<R(C::*)(Args...) const&&> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type<R(C::*)(Args...) volatile> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type<R(C::*)(Args...) volatile&> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type<R(C::*)(Args...) volatile&&> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type<R(C::*)(Args...) const volatile> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type<R(C::*)(Args...) const volatile&> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type<R(C::*)(Args...) const volatile&&> { using type = R; };
template <typename Function, typename... Args>
auto call_function(Function&& f, Args&&... args)
-> typename return_type<typename std::remove_reference<Function>::type>::type
{
return std::forward<Function>(f)(std::forward<Args>(args)...);
}
template <typename Function, typename Class, typename... Args>
auto call_member_function(Function&& f, Class* instance, Args&&... args)
-> typename return_type<typename std::remove_reference<Function>::type>::type
{
return (instance->*std::forward<Function>(f))(std::forward<Args>(args)...);
}
DEMO 3