当使用std :: result_of< F>时,模板推导失败。 [英] Template deduction fails when using 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))();
}
如何使用不同数量的参数来完成这项工作?
< 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)...);
}
参数列表(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&> {使用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)...);
}
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))();
}
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)...);
}
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)...);
}
这篇关于当使用std :: result_of< F>时,模板推导失败。的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!