我試圖找出constexprcpp11/14 中的限制。我在 CPP14-5.19-4 中發現了一些使用要求:
常量運算式要么是一個泛左值核心常量運算式,其值是指一個具有靜態存盤持續時間的物件或一個函式,要么是一個純右值核心常量運算式,其值是一個物件,對于該物件及其子物件:
- ...
- 如果物件或子物件是指標型別,則它包含另一個具有靜態存盤持續時間的物件的地址、超過此類物件末尾的地址 (5.7)、函式的地址或 空指標值。
我已經對涉及 address-of operator 的運算式運行了一些測驗(如下所示的代碼),&以確保上面參考的標準宣告的正確性。
簡單地說,我試圖獲取一個全域int變數的地址,該變數global_var是一個具有靜態存盤持續時間的物件(如果我沒有想錯的話),一切都如標準所指出的那樣作業。但是,讓我感到困惑的是,當我嘗試分配另一個指標型別物件(global_var_addr1在代碼中)時,該物件存盤了同一物件的地址global_var,該程式將無法編譯。海灣合作委員會說:
錯誤:'global_var_addr1' 的值在常量運算式中不可用
注意:'global_var_addr1' 未宣告為 'constexpr'
,而 Clang-Tidy 說:
錯誤:constexpr 變數“x2”必須由常量運算式初始化 [clang-diagnostic-error]
注意:在常量運算式中不允許讀取非 constexpr 變數“global_var_addr1”
我不知道為什么,有什么我錯過的嗎?
所以我的問題是:
1. 為什么在常量運算式中,我不能使用包含靜態存盤持續時間的物件地址的指標型別物件,正如標準所說的那樣?
2. 當auto指定物件時,為什么在與 (1) 相同的背景關系中一切都不同?
歡迎任何建議,提前致謝!
代碼:
const int global_var_c = 123;
int global_var = 123;
const void *global_var_addr1 = &global_var;
const void *global_var_addr2 = nullptr;
auto global_var_addr3 = nullptr;
auto main() -> int
{
constexpr const int x00 = global_var_c; // OK
constexpr const void *x0 = &global_var; // OK
// Operate on the object of pointer type
constexpr const void *x1 = &global_var_addr1; // OK
constexpr const void *x2 = global_var_addr1; // ERROR: read of non-constexpr variable 'global_var_addr1'...
// Operate on nullptr
constexpr const void *x3 = &global_var_addr2; // OK
constexpr const void *x4 = global_var_addr2; // ERROR: read of non-constexpr variable 'global_var_addr2'...
// Operate on nullptr (with type deduction)
constexpr const void *x5 = global_var_addr3; // OK
constexpr const void *x6 = &global_var_addr3; // OK
}
uj5u.com熱心網友回復:
同時
constexpr const void *x2 = global_var_addr1;
和
constexpr const void *x4 = global_var_addr2;
左值到右值的轉換發生在從變數global_var_addr1/global_var_addr2泛左值到它們所持有的指標值之間。僅當變數的生命周期在常量運算式的求值期間開始時才允許這種轉換(這里不是這種情況)或者如果它可用于常量運算式,這意味著它是constexpr(這里不是這種情況)或由常量運算式初始化(是這里的情況)和參考或const限定的整數/列舉型別(不是這里的情況)。
因此初始值設定項不是常量運算式。
這是不同的情況
constexpr const int x00 = global_var_c;
因為global_var_c是const-qualified 整數型別。
我不太確定
constexpr const void *x5 = global_var_addr3; // OK
直觀上它應該可以作業,因為 的型別nullptr以及由此推匯出的型別global_var_addr3是std::nullptr_t不需要攜帶任何狀態的,因此不需要左值到右值的轉換。標準是否真的保證了這一點,我目前不確定。
讀取當前措詞(后C 20草案),[conv.ptr]表示只空指標恒定的轉化率(即,prvalue的std::nullptr_t)到另一個指標型別和[conv.lval]特別指出如何左值到-rvalue 轉換std::nullptr_t產生一個空指標常量。[conv.lval] 在注釋中還澄清了這種轉換不訪問記憶體,但我認為這不會使它不是左值到右值的轉換,因為它仍然寫在該標題下。
所以在我看來,嚴格閱讀標準
constexpr const void *x5 = global_var_addr3; // OK
應該global_var_addr3是const格式錯誤的(無論是否合格)。
這是一個開放的叮當聲錯誤。標準委員會的內部討論似乎有一個鏈接,我無法訪問。
在任何情況下,auto占位符都無關緊要。你可以std::nullptr_t直接為它寫作。
所有這些都是作為核心常量運算式的要求,這是您在問題中提到的要求的先決條件。
uj5u.com熱心網友回復:
這里宣告的變數顯然不是constexpr(甚至不是const):
const void *global_var_addr1 = &global_var;
并且您不能使用非 constexpr 值來初始化 constexpr 值。所以編譯失敗也就不足為奇了:
constexpr const void *x2 = global_var_addr1; // ERROR: read of non-constexpr
非constexpr 值的地址可以在您展示的情況下使用,但是,存盤在變數中的值和變數的地址不是一回事。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/394774.html
上一篇:與std::function陣列相比boost::mp11::mp_with_index的性能
下一篇:在教程中找到的代碼的語法錯誤?
