当使用std :: result_of< F>时,模板推导失败。 [英] Template deduction fails when using std::result_of<F>

查看:95
本文介绍了当使用std :: result_of< F>时,模板推导失败。的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

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

//
//调用网站:
//

call_function(f);
call_member_function(& F :: f,& instance);

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



std :: decay std ::的不同排列的 std :: result_of



如何使

code> call_function
call_member_function 编译,最好也为返回 void

解决方案

您不需要应用 std :: remove_reference std :: decay 转换为推导的函数类型,以便与 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函数,typename类>
auto call_member_function(function&& f,Class * instance)
- > typename std :: result_of< Function(Class *)> :: type
// ~~~~~~~ ^
{
return(instance-> * std :: forward< ;函数>(f))();
}

DEMO







如何使用不同数量的参数来完成这项工作?




< p $ p> #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& ..);
}

template< typename函数,typename类,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)) :: 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 定义如下:

  = int(char,float); 

那么 std :: result_of< Function> :: type 等于:

  std :: result_of< int(char,float)> :: type 
// | | |
// | | `~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~。
// | `~~~~~~~~~~~~~~~~~~~。 |
//`~~~~~~~~。 | |
// VVV
decltype(std :: declval< int>()(std :: declval< char>(),std :: declval< float>()))
// ^ ^ ^ ~~~~~~~~~~~~~~~~~ ^
//函数调用操作符参数的实例

也就是说,在 std :: result_of 的部分特化中推导出的结果类型函子对象的实例。由于没有为 int 定义的函数调用操作符,上述尝试无法编译。



如果函数被推导为对函数的引用,那么你将得到一个不完整的主模板 std :: result_of ,因为它甚至不匹配它的任何部分特化。



如果你想获得函数的返回类型(不首先提供参数,因此 decltype()不是一个选项),您可以在函数模板参数推导过程中推导出:

  template< typename R,typename ... Params,typename ... Args> 
R call_function(R(* f)(Params ...),Args& ... args)
{
return f(std :: forward& ...);
}

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)...);
}

或通过提供单独的trait类:

  #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& ..);
}

template< typename函数,typename类,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


I am trying to make a function which calls and return the returned value of a function passed as a template parameter:

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); 

Here is a ideone version: http://ideone.com/IYM10x (it fails in a similar way in VS2013.4)

I have substituted the argument to std::result_of to different permutations of std::decay, std::remove_reference and std::remove_pointer without any luck.

How do I make call_function and call_member_function compile, preferably also for functions which return void?

解决方案

You don't need to apply a std::remove_reference or a std::decay transformation to a deduced Function type so as to use it with std::result_of. What you need is a proper syntax similar to a function call expression:

#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


How do I make this work for functions of with different number of arguments?

#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


The argument list (Args...) should already be part of Function, why do I need them again? Or rather is there a way to make std::result_of<> work without them?

Yes, a list of parameters is already a part of the deduced Function signature. The trick is, this is not how std::result_of<F> works - it only utilizes the syntax of a function declaration.

std::result_of<F> is designed to query the result type of a given functor object when called with arguments of given types.

What normally would be the result type of a function, like int for int(char,float), within std::result_of it is treated as the type of a functor object that a function call operator will be applied to. Hence, when you have a Function defined as follows:

using Function = int(char,float);

then the std::result_of<Function>::type is equal to:

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                     

That is, the result type deduced in a partial specialization of std::result_of is used to obtain an instance of a functor object. Since there is no function call operator for int defined, the above attempt fails to compile.

If the Function is deduced as a reference to function, then you end up with an incomplete primary template of std::result_of, because it doesn't even match any of its partial specializations.

If you want to get the return type of a function (without providing the arguments first, so decltype() is not an option), you can deduce it during the function template argument deduction:

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)...);
}

or by providing a separate trait class:

#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

这篇关于当使用std :: result_of&lt; F&gt;时,模板推导失败。的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆