2012-07-13 59 views
16
#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; 
} 

请解释为什么std::result_of<f(int)>::type x;无效...的std ::的result_of简单的功能

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

有什么问题?

+3

的解决方案是使用本'的std ::的result_of :: type x;'。如果您想深入了解,请查看http://stackoverflow.com/q/2763824/893693 – inf 2012-07-13 13:22:51

回答

22

std::result_of<T>要求T是一种类型 - 但不只是任何类型。 T必须是一个函数式所以result_of这部分特将被使用:

template <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不是类型 - 它是函数类型的一个实例。要声明x是应用于intf返回类型,简单地写:

decltype(f(int{})) x; 

或者如果你喜欢硬编码的int

decltype(f(32)) x; 

如果类型f然后用:

using FuncPtr = decltype(f); 

在所提供的代码F(即,不小写f)然而是一种类型的,因此F(int)限定了代表返回F受理int为参数的函数的类型。显然这不是F的意思! F的类型是一个结构,它的实例可以使用函数调用操作符。 F也没有明确或隐含的构造函数,也可以使用int等。这如何工作?简短的回答:模板“魔术”。

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

  1. F是一个指针,指向用于一些T级
  2. 一个成员函数如果只有一个参数,F是一个指针,指向类T的数据成员,或者,
  3. 一架F的实例可以作为一个功能,即,
declval<F>()(declval<int>()) 

它可以是一个普通的函数调用或某些类型的函子(例如,像您的例子)。

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

关于这件事的美妙之处在于,result_of的用户不需要知道任何有关这个实际工作方式的信息。唯一需要了解的是result_of需要一个函数TYPE。如果使用的是代码中不是类型的名称(例如,f),则需要使用decltype来获取具有这种类型的表达式的类型。

最后,为什么f不能被视为一个类型的部分原因是模板参数也允许常量值,而f是一个常量函数指针值。这是很容易证明(使用f问题的定义):

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

及更高版本:

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

因此,要获得正确调用f一些int表达式的返回值的类型一会写:

decltype(f(int{})) 

(注:f不会被调用:编译器简单地使用内decltype表达以确定其结果即在这种情况下它的返回值。)