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
为f
应用于 an的返回类型int
,只需这样写:
decltype(f(int{})) x;
或者,如果您更喜欢硬编码int
:
decltype(f(32)) x;
如果f
需要的类型,则使用:
using FuncPtr = decltype(f);
然而,在提供的代码中F
(即,不是小写f
)是一个类型,因此F(int)
定义了一个表示返回F
接受 anint
作为参数的函数的类型。显然这不是F!F
的类型是一个结构体,其实例可以使用函数调用运算符。F
也没有显式或隐式构造函数采用int
等。这怎么行?简短的回答:模板“魔术”。
本质上, 的定义std::result_of
采用类型,F(int)
并将返回类型与参数类型分开,因此它可以确定 INVOKE() 的哪种情况允许它工作。INVOKE的案例有:
- F 是指向某个类 T 的成员函数的指针
- 如果只有一个参数,则 F 是指向 T 类数据成员的指针,或者,
- F 的一个实例可以用作函数,即
declval<F>()(declval<int>())
这可以是一个普通的函数调用或某种类型的仿函数(例如,像你的例子)。
一旦确定了这一点,就可以确定result_of
有效表达式的返回类型。这是通过result_of
的type
成员返回的内容。
这样做的美妙之处在于,用户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
来确定其结果,即在此实例中的返回值。)