簡體   English   中英

關於持續初始化的困惑

[英]Confusion about constant initialization

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是必要的嗎?在標准中它說:

如果具有靜態或線程存儲持續時間的變量或臨時對象由實體的常量初始化程序初始化,則執行常量初始化。

這里標准沒有將obj指定為const-qualified / static-qualified

試圖說的是

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 它不是一個常量表達式,如果進行求值,它將具有未定義的行為。

混淆是由於命名: 常量初始化中的術語常量 [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和case4,j3和j4在編譯時沒有初始化,因為它們不適合這個最后的規則異常,因為它們沒有先前的初始化,(至少它可以在鏈接時解決,但這將是一個英雄努力或依賴於實施質量)

(1)原則是語言不應太復雜,無法編譯。 我只是回收了模板論證演繹標准的措辭,其中術語英雄的努力似乎很明顯。 應用相同的原則來定義什么是常量表達式。

“常量初始化”意味着初始化器是一個常量表達式。 表達式和變量都不需要是const限定的。

int x = 6; 在文件范圍是常量初始化。

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

如果與靜態或線程存儲持續時間的變量或臨時對象由恆定初始化為實體初始化執行恆定的初始化

在您引用的頁面中,您可以閱讀

設置靜態常量的初始值

我把注意力集中在常數上

所以T必須是一個常數類型。

所以int const就可以了; constexpr int是可以的,因為constexpr意味着const ; int沒有const (或沒有constexpr暗示const )是錯誤的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM