关于持续初始化的困惑

时间:2018-04-05 15:03:00

标签: c++ c++11 constexpr

cppref中,它提供了常量初始化的语法:

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

这是我的两个问题:

Q1

如果没有T &的左值引用const如何绑定到constexptr,这是恒定且不可修改的?

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

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

Q2

常量初始化对象是const / static的必要性吗?在the standard中它说:

  

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

此处标准未指定obj为const-qualified / static-qualified

4 个答案:

答案 0 :(得分:6)

试图说的是

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。它不是一个常量表达式,如果进行求值,它将具有未定义的行为。

答案 1 :(得分:5)

混淆是由于命名:常量初始化 [basic.start.static]/2常量表达式 {{3}中的术语常量 }表示在编译时可评估,无需编译器的英雄努力(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

发生了什么:

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

(1)原则是语言不能太复杂而无法编译。我只是回收了模板参数演绎标准的措辞,其中英雄努力一词出现了。同样的原则用于定义什么是常量表达式。

答案 2 :(得分:2)

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

文件范围内的

int x = 6;是常量初始化。

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

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

常量初始化

答案 3 :(得分:1)

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

  

设置静态常量的初始值

我将注意力集中在常数

所以T必须是常量类型。

所以int const没问题; constexpr int没问题,因为constexpr暗示const;没有int {或没有const暗示constexpr)的const是错误的。