sta*_*cpp 6 c++ language-lawyer constexpr
N4527 7.1.5 [dcl.constexpr] p9
对象声明中使用的constexpr说明符将对象声明为const.这样的对象应具有文字类型并应初始化.如果它是由构造函数调用初始化的,那么该调用应该是一个常量表达式(5.20).否则,或者如果在引用声明中使用constexpr说明符,则其初始值设定项中出现的每个完整表达式都应为常量表达式.
5.20 [expr.const] P5
常量表达式是glvalue核心常量表达式,其值指的是一个实体,它是常量表达式的允许结果(如下定义),或者是一个prvalue核心常量表达式,其值是一个对象,对于该对象及其子对象:
- 引用类型的每个非静态数据成员是指一个实体,它是一个常量表达式的允许结果,和
- 如果对象或子对象是指针类型,则它包含具有静态存储持续时间的对象的地址,超过此类对象的结尾的地址(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
}
Run Code Online (Sandbox Code Playgroud)
问题:为什么constexpr const int &a = 1;块范围失败?
这在cwg 缺陷报告 2005:不正确的 constexpr 参考初始化要求中进行了介绍(强调我的):
考虑一个例子:
Run Code Online (Sandbox Code Playgroud)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。
用左值表达式初始化的非常量 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 段已经涵盖了这个问题,其中包括分析中的转换和临时变量。
| 归档时间: |
|
| 查看次数: |
254 次 |
| 最近记录: |