关于持续初始化的困惑

big*_*iao 7 c++ constexpr c++11

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

static T & ref = constexpr; 
static T object = constexpr;    
Run Code Online (Sandbox Code Playgroud)

这是我的两个问题:

Q1

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

我试着提供一些例子,但失败了:

 static int& ref = 6; //error, need a `const`
 constexpr int a = 6; static int& ref = a; //error, need a `const`  
Run Code Online (Sandbox Code Playgroud)

Q2

对于持续初始化的对象是否必须是const/ static?在标准中它说:

执行恒定初始化如果与静态或线程存储持续时间的变量或临时对象由恒定初始化为实体初始化.

这里标准没有将obj指定为const-qualified/ static-qualified.

小智 6

试图说的是

static int a;
static int & ref = a;
static_assert(&a == &ref, "");
Run Code Online (Sandbox Code Playgroud)

没关系.初始化是一种常量初始化的形式,因为a当作为左值(但仅作为左值!)进行求值时,它&a == &ref是一个常量表达式,因此,它是一个求值为的常量表达式true.

比较这个

void f() {
  int a;
  static int & ref = a;
  static_assert(&a == &ref, "");
}
Run Code Online (Sandbox Code Playgroud)

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


Oli*_*liv 5

的混乱是由于命名:术语恒定恒定的初始化 [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;
Run Code Online (Sandbox Code Playgroud)

由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
Run Code Online (Sandbox Code Playgroud)

发生了什么:

  • 情况0,j0未在编译时初始化,因为i0不是常量.[expr.constant] /2.7
  • 情况1和2,是编译时初始化的,因为它们适用于先前规则[expr.constant] /2.7.3的例外.
  • 情况3和case4,j3和j4在编译时没有初始化,因为它们不适合这个最后的规则异常,因为它们没有先前的初始化,(至少它可以在链接时解决,但这将是一个英雄努力或依赖于实施质量)

(1)原则是语言不应太复杂,无法编译.我只是回收了模板论证演绎标准的措辞,其中术语英雄的努力似乎很明显.应用相同的原则来定义什么是常量表达式.