C++17 和 C++11 中的非类型模板参数有什么区别?

Gha*_*ani 11 c++ language-lawyer non-type c++11 c++17

考虑这个代码:

using func = int (*)(int, int);

template<func F>
void do_something(int first, int second) {}

int something(int first, int second) { return 42; }

void  f()
{
  constexpr auto  function = something;
  do_something<function>(10, 20);
}
Run Code Online (Sandbox Code Playgroud)

它是用 C++17 标准兼容编译器编译和运行的,但它在 C++11 标准下失败:

 error: no matching function for call to ‘do_something<function>(int, int)’
   17 |   do_something<function>(10, 20);
Run Code Online (Sandbox Code Playgroud)

C++11 非类型模板参数和 C++17 非类型模板参数有什么区别?在 §14.1.4 [temp.param][n3690] 中:

非类型模板参数应具有以下(可选 cv 限定的)类型之一:
— 整数或枚举类型,
— 指向对象或函数的指针,— 指向对象的
左值引用或指向函数的左值引用,
— 指向成员,
——std::nullptr_t。

在 §17.1.4 [temp.param][n4713] 中:

非类型模板参数应具有以下(可选 cv 限定的)类型之一:
(4.1) — 整数或枚举类型,
(4.2) — 指向对象或函数的指针,
(4.3) — 对对象的左值引用或对函数的左值引用,
(4.4) — 成员指针,
(4.5) — std::nullptr_t,或
(4.6) — 包含占位符类型 (10.1.7.4) 的类型。

唯一的区别是:

< — 包含占位符类型的类型 (10.1.7.4)。

我认为这与我的问题无关,因为占位符类型类似于auto,并且我向模板发送了一个值,而不是占位符类型或类型。

asc*_*ler 5

相关的区别在于对 [temp.arg.nontype] 中允许的模板参数(不是模板参数)的要求。

C++11:

模板参数的用于非类型,非模板模板参数应是以下之一:

  • ...
  • 一个常量表达式,指定具有静态存储持续时间和外部或内部链接的对象的地址或具有外部或内部链接的函数,包括函数模板和函数模板 id但不包括非静态类成员,表示(忽略括号)作为& id-expression,但&如果名称引用函数或数组,则可以省略,如果相应的模板参数是引用,则应省略;或者
  • ...

C++17

模板参数的用于非类型模板参数应为的类型的一个转换后的常量表达式模板参数。对于引用或指针类型的非类型模板参数,常量表达式的值不得引用(或对于指针类型,不得为以下地址):

  • 一个子对象,
  • 一个临时对象,
  • 字符串文字,
  • typeid表达式的结果,或
  • 预定义的__func__变量。

在 C++11 中,模板参数 function不是& id-expression的形式,并且名称不引用函数something。它指的是一个类型为 的变量int (*const)(int, int),其值指向something。(并且do_something<&function>无济于事,因为现在您有一个指向函数指针的指针,它不会转换为指向函数类型的指针。)

在 C++17 中,语法要求消失了,并且限制是对哪些对象不能指向或引用的更宽松的纯语义要求。