为什么`constexpr const int& a = 1;`在块范围内失败?

时间:2015-07-20 15:04:54

标签: c++ language-lawyer constexpr

N4527 7.1.5 [dcl.constexpr] p9

  

对象声明中使用的constexpr说明符将对象声明为const。这样的对象应具有文字类型并应初始化。如果它是由构造函数调用初始化的,那么该调用应该是一个常量   表达式(5.20)。 否则,或者如果在引用声明中使用constexpr说明符,则其初始值设定项中出现的每个完整表达式都应为常量表达式。

5.20 [expr.const] P5

  

常量表达式是glvalue核心常量表达式,其值指的是一个实体   允许的常量表达式结果(如下定义),或者是一个prvalue核心常量表达式   value是一个对象,对于该对象及其子对象:

     

- 引用类型的每个非静态数据成员引用一个实体,该实体是常量表达式的允许结果,并且

     

- 如果对象或子对象是指针类型,则它包含具有静态存储持续时间的对象的地址,超过此类对象末尾的地址(5.7),函数的地址或空指针值

     

实体是常量表达式的允许结果,如果它是具有静态存储持续时间的对象,该对象不是临时对象,或者是其值满足上述约束的临时对象,或者它是   功能

void foo(){
    constexpr const int &a = 1;//error
    constexpr static const int &b = 1;//ok in gcc 5.1.0 and clang 3.8.0

}

问题:为什么constexpr const int &a = 1;在块范围内失败?

1 个答案:

答案 0 :(得分:4)

cwg defect report 2005: Incorrect constexpr reference initialization requirements中说明了这一点(强调我的):

  

考虑一个例子:

  constexpr int f() { return 5; } // function must be constexpr
  constexpr int && q = f();       // but result is not constant
  constexpr int const & r = 2;    // temporary is still not constant
  int main() {
    q = 11;                       // OK
    const_cast< int & >( r ) = 3; // OK (temporary object is not ROMable)

    constexpr int && z = 7;       // Error? Temporary does not have static storage duration?
  }
     

constexpr引用必须通过常量表达式初始化   (7.1.5 [dcl.constexpr]第9段),但它可以指可修改的   临时对象。这样的临时保证是静态的   初始化,但它不是ROMable。

     

使用左值表达式初始化的非const constexpr引用   很有用,因为它表明了底层存储的   引用可能是静态初始化的,或者没有底层存储   完全是必需的。

     

当初始化程序是临时的时,查找其地址是微不足道的。   没有理由声明其计算任何意图   地址。另一方面,提供初始值,即   虽然它从未被处理过,但也需要不断表达   作为常数。

     

本地constexpr参考的情况更糟。初始化程序   在执行声明时生成临时值。暂时的   是一个本地作用域,唯一的对象。这使得constexpr   没有意义,因为虽然地址计算是微不足道的,但它   仍然必须动态完成。

     

C ++ 11 constexpr引用需要通过引用进行初始化   常量表达式,必须“用静态指定一个对象   存储持续时间或函数“(C ++ 11 5.20 [expr.const]第3段)。   由引用授予的临时自动存储持续时间   没有这个要求。

     

C ++ 14删除了引用常量表达式和静态存储   要求,明确地使用明确定义的程序   击败了constexpr说明者。 (GCC和Clang目前提供   C ++ 11诊断。)

     

建议解决方案:临时绑定到constexpr引用   应该是constexpr,意味着const限定类型。禁止   将constexpr引用绑定到临时,除非两者都有静态   储存期限。 (在本地范围内,静态说明符修复了   问题很好。)

答案是5.20第4段已禁止这样做:

  

5.20 [expr.const]第4段已涵盖此问题,其中包括分析中的转换和临时工具。