使用std :: result_of <F>时,模板推断失败

mau*_*uve 1 c++ templates type-deduction

我正在尝试创建一个函数,该函数调用并返回作为模板参数传递的函数的返回值:

template <typename Function>
typename std::result_of<Function>::type
call_function(Function&& f)
{
  return f();
}

template <typename Function, typename Class>
typename std::result_of<Function>::type
call_member_function(Function&& f, Class* instance)
{
  return instance->*f();
}

//
// call site:
//

call_function(f);
call_member_function(&F::f, &instance); 
Run Code Online (Sandbox Code Playgroud)

这是一个ideone版本:http://ideone.com/IYM10x (它在VS2013.4中以类似的方式失败)

我已经将论证替换std::result_of为不同的排列std::decay,std::remove_reference并且std::remove_pointer没有任何运气.

我如何制作call_functioncall_member_function编译,最好还为返回的函数void

Pio*_*cki 5

您不需要对推导类型应用std::remove_referencestd::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))();
}
Run Code Online (Sandbox Code Playgroud)

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)...);
}
Run Code Online (Sandbox Code Playgroud)

演示2


参数列表(Args ...)应该已经是Function的一部分,为什么我需要它们呢?或者更确切地说,有没有办法让std :: result_of <>在没有它们的情况下工作?

是的,参数列表已经是推断Function签名的一部分.诀窍是,这不是如何std::result_of<F>工作 - 它只使用函数声明的语法.

std::result_of<F> 用于在使用给定类型的参数调用时查询给定仿函数对象的结果类型.

什么通常会是结果类型的功能,如intint(char,float),内std::result_of它是作为一个函数调用操作将被应用到一个函子对象的类型进行处理.因此,当您Function定义如下:

using Function = int(char,float);
Run Code Online (Sandbox Code Playgroud)

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                     
Run Code Online (Sandbox Code Playgroud)

也就是说,在部分特化中推导出的结果类型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)...);
}
Run Code Online (Sandbox Code Playgroud)

或者通过提供单独的特质类:

#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)...);
}
Run Code Online (Sandbox Code Playgroud)

演示3

  • 或者简单地使用` - > decltype(f())`,` - > decltype((instance - >*f)())`. (2认同)