[英]Confusion about constant initialization
在cppref中,它給出了常量初始化的語法:
static T & ref = constexpr;
static T object = constexpr;
這是我的兩個問題:
如何將左值引用T &
沒有const
綁定到constexptr
,這是恆定且不可修改的?
我試着提供一些例子,但失敗了:
static int& ref = 6; //error, need a `const`
constexpr int a = 6; static int& ref = a; //error, need a `const`
常量初始化的對象是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
發生了什么:
(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.