对常量初始化的困惑



在cppref中,它给出了常量初始化的语法:

static T & ref = constexpr; 
static T object = constexpr;    

这是我的两个问题:

第一季度

没有const的左值引用怎么可能T &绑定到一个常量且不可修改的constexptr

我尝试提供一些示例,但失败了:

static int& ref = 6; //error, need a `const`
constexpr int a = 6; static int& ref = a; //error, need a `const`  

第 2 季度

常量初始化的对象是否有必要const/static?在标准中它说:

如果具有静态或线程存储持续时间的变量或临时对象由实体的常量初始值设定项初始化,则执行常量初始化。

此处标准未指定要const-qualified/static-qualified的对象。

混淆是由于命名造成的:常量初始化中的术语常量[basic.start.static]/2 和常量表达式[expr.const] 表示在编译时可评估,而无需编译器的英勇努力(1)。这与常量对象的概念不同,常量对象的概念意味着对象的值一旦定义就不会改变。

为了说明编译时计算的限制,让我们看一下这段代码的汇编:

//case 0
int i0 = 5;
int j0 = i0;//no compil-time initialized
//case 1
const int i1=5; 
int j1=i1; //compil-time initialized
//case 2
extern const int i2=5; 
int j2=i2; //compile-time initialized
//case 3
extern const int i3; 
int j3=i3; //no compil-time initialization
//case 4
extern const int i4; 
int j4=i4; //no compil-time initialization
const int i4=5;

由 gcc 7.3 生成的程序集:

_GLOBAL__sub_I_example.cpp: # @_GLOBAL__sub_I_example.cpp
mov eax, dword ptr [rip + i0]
mov dword ptr [rip + j0], eax
mov eax, dword ptr [rip + i3]
mov dword ptr [rip + j3], eax
mov dword ptr [rip + j4], 5
ret

正在发生什么:

  • 在 0 的情况下,J0 在编译时未初始化,因为 i0 不是常量。expr.constant]/2.7
  • 情况 1 和 2 是编译时初始化的,因为它们符合前一条规则 [expr.constant]/2.7.3 的例外。
  • 案例 3 和案例 4,J3 和 J4 在编译时没有初始化,因为它们不适合最后一个规则例外,因为它们没有前面的初始化,(至少它可以在链接时解决,但这将是一个英勇的努力或取决于实现质量)

(1)原则是语言不能太复杂而无法编译。我只是重复了模板参数推理标准的措辞,其中英勇努力一词随处可见。同样的原则也用于定义什么是常量表达式。

这想说的是

static int a;
static int & ref = a;
static_assert(&a == &ref, "");

没关系。初始化是常量初始化的一种形式,因为当评估为左值(但仅作为左值!)时a是一个常量表达式,因此,&a == &ref是一个常量表达式,其计算结果为true

将此与

void f() {
int a;
static int & ref = a;
static_assert(&a == &ref, "");
}

这是无效的。尽管ref的初始化在技术上是有效的,但一旦函数返回,它就会成为一个悬而未决的引用。下次输入函数时,将创建一个新的int a对象。正因为如此,&a == &ref不能保证评估到true。它不是一个常量表达式,如果评估,将具有未定义的行为。

">

常量初始化"表示初始值设定项是一个常量表达式。表达式和变量都不需要进行常量限定。

文件范围内的int x = 6;是常量初始化。

参考: C++17 [basic.start.static]/2:

如果具有静态或线程存储持续时间的变量或临时对象由实体的常量初始值设定项初始化,则执行常量初始化

在您引用的页面中,您可以阅读

设置静态常量的初始值

我把你的注意力放在常量

所以T必须是常量类型。

所以int const没关系;constexpr int是可以的,因为constexpr暗示const; 没有const(或没有暗示constconstexpr)的int是错误的。

最新更新