括号使指针模板参数无效吗?

asc*_*ler 7 c++ templates language-lawyer

考虑以下代码:

int x = 0;

template<int& I>
struct SR {};

template<int* I>
struct SP {};

SR<(x)> sr;
SP<&(x)> sp;

int main(void)
{
}
Run Code Online (Sandbox Code Playgroud)

clang ++ 3.8.0抱怨:

main.cpp:10:5: error: non-type template argument does not refer to any declaration
SP<&(x)> sp;
    ^~~
main.cpp:6:15: note: template parameter is declared here
template<int* I>
              ^
Run Code Online (Sandbox Code Playgroud)

g ++ 6.1.0抱怨:

main.cpp:10:8: error: template argument 1 is invalid
 SP<&(x)> sp;
        ^
Run Code Online (Sandbox Code Playgroud)

当然,如果我删除括号,一切正常,如SP<&x> sp;.但是我在C++ 14标准中找不到任何会在这里产生影响的东西.此外,为什么参考案例没问题,但指针案例不好?编译器是否正确拒绝该程序?

Bri*_*ian 4

我对标准的解读是它应该被允许,但我认为 GCC 和 Clang 的实现者不同意我的解释,他们可能是正确的。要获得明确的答案,最好询问 std-discussion@isocpp.org 邮件列表(我会向他们发送一封电子邮件)。措辞可能有缺陷。

根据 [temp.arg.nontype],非类型模板参数的可能形式之一是:

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

这一切都取决于“忽略括号”的含义。GCC 和 Clang 都接受(&x)但不接受&(x);他们似乎已经决定“忽略括号”仅意味着在外部,而不是在id 表达式周围。如果这是标准委员会的意图,则应澄清语言。

编辑:C++17 草案中,这是明确允许的,因为允许的非类型模板参数的形式已大大放宽:

非类型模板参数的模板参数应为模板参数类型的转换常量表达式 ([expr.const]) 。对于引用或指针类型的非类型模板参数,常量表达式的值不应引用(或对于指针类型,不应是以下地址):

  • 一个子对象([intro.object]),
  • 一个临时对象([class.temporary]),
  • 字符串文字 ([lex.string]),
  • 表达式的结果typeid([expr.typeid]),或
  • 预定义__func__变量 ([dcl.fct.def.general])。