引用为非类型模板参数

时间:2015-02-22 20:22:16

标签: c++ c++11 language-lawyer

下面的示例尝试使用引用类型的变量作为非类型模板参数(本身为引用类型)的参数。 Clang,GCC和VC ++都拒绝它。但为什么?我似乎无法在标准中找到任何使其成为非法的内容。

int obj = 42;
int& ref = obj;

template <int& param> class X {};

int main()
{
    X<obj> x1;  // OK
    X<ref> x2;  // error
}

Live example


克朗说:

  

source_file.cpp:9:7:错误:引用类型的非类型模板参数&#39; int&amp;&#39;不是一个对象

其他人以类似的方式抱怨。


从标准(C ++ 11的所有引用; C ++ 14似乎没有相关部分的重大变化):

  

14.3.2 / 1 非类型非模板模板参数 template-argument 应为以下之一:

     

...

     
      
  • 一个常量表达式(5.19),用于指定具有静态存储持续时间和外部或内部链接的对象的地址...表达(忽略括号)为& id-expression ,除了如果相应的 template-parameter 是参考<{li>,& ...将被省略   
     

...

现在是一个常数表达式:

  

5.19 / 2 条件表达式核心常量表达式,除非它涉及下列其中一项作为潜在评估的子表达式(3.2) )...

     

...

     
      
  • id-expression ,引用引用类型的变量或数据成员,除非引用具有先前的初始化,使用常量表达式初始化
  •   
     

...


据我所知,ref中的X<ref> id-expression ,它引用了引用类型的变量。此变量具有先前的初始化,使用表达式obj初始化。我相信obj是一个不变的表达式,无论如何,如果它不是,那么X<obj>也不应该编译。

  • 那我错过了什么?
  • 标准中的哪个子句呈现X<ref>无效,而X<obj>有效?

1 个答案:

答案 0 :(得分:8)

简介

正确的说法是引用的名称是 id-expression ; id-expression 不引用引用所引用的内容,而是引用引用本身。

 int    a = 0;
 int& ref = a; // "ref" is an id-expression, referring to `ref` - not `a`

标准(N4140

您在帖子中引用了标准的相关部分,但是您遗漏了最重要的部分(强调我的):

  

14.3.2p1 模板非类型参数 [temp.arg.nontype]

     

非类型非模板模板参数 template-argument 应为以下之一:

     
      
  • <子> ...

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

  •   


注意:在早期草稿中“其中id-expression是对象或函数的名称”不存在;它由DR 1570解决 - 这无疑使意图更加明确。


引用类型的变量不是对象

你是绝对正确的;引用本身具有引用类型,并且只能在表达式的一部分时充当对象。

  

5p5 表达式 [expr]

     

如果表达式最初具有“T引用”类型(8.3.2,8.5.3),则在进行任何进一步分析之前将类型调整为&id-expression。表达式指定由引用表示的对象或函数,表达式是左值或x值,具体取决于表达式。


精化

非常重要的是要注意常量表达式“指定完整对象的地址......”)必须是{{1}之一},或id-expression

即使常量表达式(不仅仅是 id-expression )可能引用具有静态存储持续时间的对象,我们也无法将其用于< em>“初始化” 引用的模板参数 - 指针类型

示例代码段

template<int&>
struct A { };

int            a = 0;
constexpr int& b = (0, a); // ok, constant-expression
A<(0, a)>      c = {};     // ill-formed, `(0, a)` is not an id-expression

注意:这也是我们无法将 string-literals 用作 template-arguments 的原因;它们不是 id-expressions

相关问题