c – 使用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();
}

所以(不确定编译器版本):

铿锵 – 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
returning T” is adjusted to be of type “pointer to T” or “pointer to
function returning T”, respectively.

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

using df = decltype(&f);

Demo.

为什么使用df = decltype((f));工作?

[dcl.type.simple] / 4:

For an expression e, the type denoted by decltype(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 by e. 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) is T&&, where T is the type of e;
  • otherwise, if e is an lvalue, decltype(e) is T&, where T is the type of e;
  • otherwise, decltype(e) is the type of e.

(f)括号和左值,因此decltype((f))是f函数类型的左值引用 – void(&)(int).模板参数可以引用函数类型,因此它可以工作.然而,由于这个事实非常违反直觉(并且不是很清楚),因此decltype(& f)在代码中应该不那么刺激.

上一篇:c – 为什么“return(str);”​​推断出与“return str”不同的类型?


下一篇:c – 条件表达式中的右值引用