使用decltype为函数生成的非类型模板参数

时间:2015-01-07 01:43:48

标签: c++ templates language-lawyer decltype

我想用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.

1 个答案:

答案 0 :(得分:5)

非类型模板参数不能具有函数类型。它们可以有指向函数类型的指针,标准中有一个段落暗示你的代码是正确的 - [temp.param] / 8:

  

类型为“T数组”或“函数”的非类型模板参数   返回T“被调整为”指向T的指针“或”指针指向   函数分别返回T“。

但是,目前尚不清楚这是在模板参数替换之后还是之前完成的,这是覆盖in this defect report。一个简单的解决方法是简单地写

using df = decltype(&f);

Demo


为什么using df = decltype((f));有效?

[dcl.type.simple] / 4:

  

对于表达式edecltype(e)表示的类型定义为   如下:

     
      
  • 如果e未加密码的 id-expression 或未加密码的类成员访问权限(5.2.5),则decltype(e)是实体   由e命名。如果没有这样的实体,或者e命名一组   重载函数,程序格式不正确;
  •   
  • 否则,如果e是xvalue,则decltype(e)T&&T的类型为e;
  •   
  • 否则,如果e是左值,decltype(e)T&,其中Te的类型;
  •   
  • 否则,decltype(e)e
  • 的类型   

(f)带有括号和左值,因此decltype((f))f函数类型的左值引用 - void(&)(int)。模板参数可以引用函数类型,因此它可以工作。但是,由于这个事实非常违反直觉(而且不是那么众所周知),decltype(&f)在您的代码中应该不那么刺激。