我想用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();
}
所以(不太确定编译器版本):
clang - 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.
答案 0 :(得分:5)
非类型模板参数不能具有函数类型。它们可以有指向函数类型的指针,标准中有一个段落暗示你的代码是正确的 - [temp.param] / 8:
类型为“
T
数组”或“函数”的非类型模板参数 返回T
“被调整为”指向T
的指针“或”指针指向 函数分别返回T
“。
但是,目前尚不清楚这是在模板参数替换之后还是之前完成的,这是覆盖in this defect report。一个简单的解决方法是简单地写
using df = decltype(&f);
using df = decltype((f));
有效?[dcl.type.simple] / 4:
对于表达式
e
,decltype(e)
表示的类型定义为 如下:
- 如果
e
是未加密码的 id-expression 或未加密码的类成员访问权限(5.2.5),则decltype(e)
是实体 由e
命名。如果没有这样的实体,或者e命名一组 重载函数,程序格式不正确;- 否则,如果
e
是xvalue,则decltype(e)
为T&&
,T
的类型为e
;- 否则,如果
e
是左值,decltype(e)
是T&
,其中T
是e
的类型;- 否则,
的类型decltype(e)
是e
。
(f)
带有括号和左值,因此decltype((f))
是f
函数类型的左值引用 - void(&)(int)
。模板参数可以引用函数类型,因此它可以工作。但是,由于这个事实非常违反直觉(而且不是那么众所周知),decltype(&f)
在您的代码中应该不那么刺激。