简体   繁体   English

关于持续初始化的困惑

[英]Confusion about constant initialization

In cppref it gives the syntax of constant initialization : cppref中,它给出了常量初始化的语法:

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

Here's my two questions: 这是我的两个问题:

Q1 Q1

How could a lvalue reference T & without const be bound to a constexptr ,which is constant and unmodifiable ? 如何将左值引用T &没有const绑定到constexptr ,这是恒定且不可修改的?

I try to provide some example but failed: 我试着提供一些例子,但失败了:

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

Q2 Q2

Is it a necessity for the object of constant initialization to be const / static ?In the standard it says: 常量初始化的对象是const / static是必要的吗?在标准中它说:

Constant initialization is performed if a variable or temporary object with static or thread storage duration is initialized by a constant initializer for the entity. 如果具有静态或线程存储持续时间的变量或临时对象由实体的常量初始化程序初始化,则执行常量初始化。

Here the standard does not specify the obj to be const-qualified / static-qualified . 这里标准没有将obj指定为const-qualified / static-qualified

What that is trying to say is that 试图说的是

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

is okay. 没关系。 The initialisation is a form of constant initialisation because a is a constant expression when evaluated as an lvalue (but only as an lvalue!), and as a result of that, &a == &ref is a constant expression which evaluates to true . 初始化是一种常量初始化的形式,因为当作为左值(但仅作为左值!)进行求值时, a是一个常量表达式,因此, &a == &ref是一个求值为true的常量表达式。

Compare this to 比较这个

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

This is invalid. 这是无效的。 Although the initialisation of ref is technically valid, it becomes a dangling reference as soon as the function returns. 虽然ref的初始化在技术上是有效的,但是一旦函数返回它就会成为悬空引用。 The next time the function is entered, a new int a object is created. 下次输入该函数时,将创建一个新的int a对象。 Because of that, &a == &ref is not guaranteed to evaluate to true . 因此, &a == &ref不能保证评估为true It is not a constant expression, and would have undefined behaviour if evaluated. 它不是一个常量表达式,如果进行求值,它将具有未定义的行为。

The confusion is due to the naming: the term constant in constant initialization [basic.start.static]/2 and constant expression [expr.const] means evaluable at compile time without heroic efforts(1) of the compiler . 混淆是由于命名: 常量初始化中的术语常量 [basic.start.static] / 2常量表达式 [expr.const]意味着在编译时可以在没有编译器的英雄努力(1)的情况下进行评估 This differs from the concept of a constant object which means that the value of the object will not changed once defined. 这与常量对象的概念不同,这意味着一旦定义,对象的值就不会改变。

To illustrate the limit of evaluation at compile time let's look at the assembly of this code: 为了说明编译时的评估限制,让我们看一下这段代码的程序集:

//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;

Generated assembly by gcc 7.3: 由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

What is happening for: 发生了什么:

  • case 0, j0 is not initialized at compil-time because i0 is not a constant. 情况0,j0未在编译时初始化,因为i0不是常量。 [expr.constant]/2.7 [expr.constant] /2.7
  • case 1 and 2, are compil-time initialized because they fit to an exception of the previous rule [expr.constant]/2.7.3 . 情况1和2,是编译时初始化的,因为它们适用于先前规则[expr.constant] /2.7.3的例外
  • case 3 and case4, j3 and j4 are not initialized at compil-time because they do not fit to this last rule exception because they have not a preceding initialization, (at least it could be solved at link time, but this would be an heroic effort or dependent of the implementation quality) 情况3和case4,j3和j4在编译时没有初始化,因为它们不适合这个最后的规则异常,因为它们没有先前的初始化,(至少它可以在链接时解决,但这将是一个英雄努力或依赖于实施质量)

(1) the principle is that the language shall not be too complex to compile. (1)原则是语言不应太复杂,无法编译。 I just recycled the wording of the standard for template argument deduction where the term heroic effort appears litteraly. 我只是回收了模板论证演绎标准的措辞,其中术语英雄的努力似乎很明显。 The same principle is applied to define what is a constant expression. 应用相同的原则来定义什么是常量表达式。

"constant initialization" means the initializer is a constant expression. “常量初始化”意味着初始化器是一个常量表达式。 Neither the expression nor the variable need to be const-qualified. 表达式和变量都不需要是const限定的。

int x = 6; at file scope is constant initialization. 在文件范围是常量初始化。

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

Constant initialization is performed if a variable or temporary object with static or thread storage duration is initialized by a constant initializer for the entity. 如果与静态或线程存储持续时间的变量或临时对象由恒定初始化为实体初始化执行恒定的初始化

In the page you reference you can read 在您引用的页面中,您可以阅读

Sets the initial values of the static constants 设置静态常量的初始值

I point your attention over constants 我把注意力集中在常数上

So T must be a constant type. 所以T必须是一个常数类型。

So int const is OK; 所以int const就可以了; constexpr int is OK because constexpr imply const ; constexpr int是可以的,因为constexpr意味着const ; int without const (or without constexpr that imply const ) is wrong. int没有const (或没有constexpr暗示const )是错误的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM