std :: result_of简单函数 [英] std::result_of simple function

查看:179
本文介绍了std :: result_of简单函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  #include< iostream> 
#include< type_traits>

double f(int i)
{
return i + 0.1;
}

struct F
{
public:
double operator()(int i){return i + 0.1; }
};

int
main(int,char **)
{
std :: result_of< F(int)> :: type x; // ok
// std :: result_of< f(int)> :: type x; //错误:模板参数1无效
x = 0.1;
std :: cerr<< x<< std :: endl;
}

请解释为什么 std :: result_of< f int)> :: type x; 无效...



cppreference说( std :: result_of )在编译类型中推导函数调用表达式的返回类型。



有什么问题?

解决方案

std :: result_of< T> 需< c> T 是一个类型 - 但不只是任何类型。 T 必须是函数类型,因此将使用 result_of 的部分特化:

 模板< class Fn,class ... ArgTypes> struct result_of< Fn(ArgTypes ...)> ;; 

以便:

  decltype(INVOKE(declval< Fn>(),declval< ArgTypes>()...))

格式良好(C ++ 11 20.9.7.6)。 (INVOKE在20.8.2中定义。)



原因 std :: result_of< f(int)> 不工作是因为 f 不是一个类型--it是一个函数类型的实例。声明 x 是应用于 int f $ c>,只需写下:

  decltype(f(int {}))x ; 

或者如果你喜欢硬编码 int

  decltype(f(32))x; 

如果需要 f 使用:

 使用FuncPtr = decltype(f); 

在提供的代码 F 不是小写 f )但是是一个类型,因此 F(int)定义了一个类型, F 接受 int 作为参数。显然这不是什么F是! F 的类型是一个结构体,其实例可以使用函数调用操作符。 F 也没有显式或隐式构造函数接受 int 等。这如何工作?



基本上, std :: result_of 的定义采用类型, code> F(int)并将返回类型与参数类型分开,以便它可以确定INVOKE()的哪种情况允许它工作。 INVOKE的情况是:


  1. F是指向某个类T的成员函数的指针

  2. 如果只有一个参数,F是指向类T的数据成员的指针,

  3. F的实例可以用作函数,即





  declval< F>()(declval< int>()) 

这可以是一个普通的函数调用或某种类型的函子/ p>

一旦确定 result_of ,就可以确定有效表达式的返回类型。这是通过 result_of 类型成员返回的内容。



关于这一点的美好的事情是, result_of 的用户不需要知道这是如何工作的任何东西。唯一需要理解的是 result_of 需要一个TYPE函数。如果使用不是代码中的类型的名称(例如, f ),则需要使用 decltype 获得具有这样的表达式的类型。



最后,不能将 f 视为类型的部分原因是模板参数也允许常量值和 f 是常量函数指针值。这很容易演示(使用问题的定义 f ):

  template< double Op(int)> 
double invoke_op(int i)
{
return Op(i);
}

及更高版本:



b
$ b

  std :: cout< invoke_op< f>(10)< std :: endl; 

所以要获得正确调用 f 的表达式的返回值类型, code>与一些 int 一起写:

  decltype(f(int {}))

c $ c> f 从不被调用:编译器只需使用 decltype 中的表达式来确定其结果,即其在此实例中的返回值。 )


#include <iostream>
#include <type_traits>

double f(int i)
{
        return i+0.1;
}

struct F
{
        public:
        double operator ()(int i) { return i+0.1; }
};

int
main(int, char**)
{
        std::result_of<F(int)>::type x;     // ok
        // std::result_of<f(int)>::type x; // error: template argument 1 is invalid
        x = 0.1;
        std::cerr << x << std::endl;
}

Please explain why std::result_of<f(int)>::type x; is invalid...

cppreference says "(std::result_of) Deduces the return type of a function call expression at compile type.".

what's the problem?

解决方案

std::result_of<T> requires T to be a type --but not just any type. T must be a function type so this partial specialization of result_of will be used:

template <class Fn, class... ArgTypes> struct result_of<Fn(ArgTypes...)>;

such that:

decltype(INVOKE(declval<Fn>(), declval<ArgTypes>()...))

is well-formed (C++11 20.9.7.6). (INVOKE is defined in 20.8.2.)

The reason std::result_of<f(int)> does not work is because f is not a type --it is an instance of a function type. To declare x to be the return type of f applied to an int, simply write this:

decltype(f(int{})) x;

or if you prefer hard-coding an int:

decltype(f(32)) x;

If the type of f is desired then use:

using FuncPtr = decltype(f);

In the provided code F (i.e., not lower case f) however is a type and so F(int) defines a the type representing the function that returns F accepting an int as an argument. Clearly this is not what F is! F's type is a struct whose instances can use the function call operator. F also has no explicit or implicit constructors taking an int, etc. as well. How can this work? Short answer: Template "magic".

Essentially, the definition of std::result_of takes the type, F(int) and separates the return type from the argument types so it can determine which case of INVOKE() would allow it to work. The cases of INVOKE are:

  1. F is a pointer to a member function for some class T
  2. If there is only one argument, F is a pointer to a data member of class T, or,
  3. An instance of F can be used as a function, i.e.,

declval<F>()(declval<int>())

which can be a normal function call or some type of functor (e.g., like your example).

Once this has been determined result_of can then determine the return type of the valid expression. This is what is returned via result_of's type member.

The beautiful thing about this is that the user of result_of need not know anything about how this actually works. The only thing one has to understand is that result_of needs a function TYPE. If one is using names that are not types within code (e.g., f) then decltype will need to be used to obtain the type of an expression with such.

Finally, part of the reason why f cannot be considered as a type is because template parameters also allow constant values and f is a constant function pointer value. This is easily demonstrated (using the question's definition of f):

template <double Op(int)>
double invoke_op(int i)
{
  return Op(i);
}

and later:

std::cout << invoke_op<f>(10) << std::endl;

So to obtain the return value type of an expression properly invoking f with some int one would write:

decltype(f(int{}))

(Note: f is never called: the compiler simply uses the expression within decltype to determine its result i.e., its return value in this instance.)

这篇关于std :: result_of简单函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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