我想用decltype替换写函数签名,发现它不能用大多数编译器编译.这是一个新功能还是未指定的行为?
#include <iostream>
template <typename T, T nontype>
struct CL {
void call() { nontype(123); }
};
void f(int n) {
std::cout << n << std::endl;
}
CL<void(*)(int), f> cl7;
using df = decltype(f);
CL<df, f> cl8; // << error
int main() {
cl8.call();
}
所以(不确定编译器版本):
铿锵 – 3.4
http://rextester.com/UOIV91915
编译,运行,产生输出
g 4.9
http://coliru.stacked-crooked.com/a/dbec1e202c48fd81
main.cpp:14:9: error: 'void(int)' is not a valid type for a template non-type parameter
CL<df, f> cl8; // << error
^
main.cpp:14:14: error: invalid type in declaration before ';' token
CL<df, f> cl8; // << error
^
main.cpp: In function 'int main()':
main.cpp:17:6: error: request for member 'call' in 'cl8', which is of non-class type 'int'
cl8.call();
Visual Studio 2013 – 更新4
fatal error C1001: An internal error has occurred in the compiler.
解决方法:
非类型模板参数不能具有函数类型.它们可以有指向函数类型的指针,标准中有一个段落暗示你的代码是正确的 – [temp.param] / 8:
A non-type template-parameter of type “array of
T
” or “function
returningT
” is adjusted to be of type “pointer toT
” or “pointer to
function returningT
”, respectively.
但是,目前尚不清楚这是在模板参数替换之后还是在它之前完成的,它被覆盖了in this defect report.一个简单的解决方法是简单地写
using df = decltype(&f);
Demo.
为什么使用df = decltype((f));工作?
[dcl.type.simple] / 4:
For an expression
e
, the type denoted bydecltype(e)
is defined as
follows:
- if
e
is an unparenthesized id-expression or an unparenthesized class member access (5.2.5),decltype(e)
is the type of the entity
named bye
. If there is no such entity, or if e names a set of
overloaded functions, the program is ill-formed;- otherwise, if
e
is an xvalue,decltype(e)
isT&&
, whereT
is the type ofe
;- otherwise, if
e
is an lvalue,decltype(e)
isT&
, whereT
is the type ofe
;- otherwise,
decltype(e)
is the type ofe
.
(f)括号和左值,因此decltype((f))是f函数类型的左值引用 – void(&)(int).模板参数可以引用函数类型,因此它可以工作.然而,由于这个事实非常违反直觉(并且不是很清楚),因此decltype(& f)在代码中应该不那么刺激.