最近我很驚訝以下代碼也可以在 clang、gcc 和 msvc 中編譯(至少在它們的當前版本中)。
struct A {
static const int value = 42;
};
constexpr int f(A a) { return a.value; }
void g() {
A a; // Intentionally non-constexpr.
constexpr int kInt = f(a);
}
我的理解是呼叫f不是 constexpr 因為引數i不是,但似乎我錯了。這是適當的標準支持代碼還是某種編譯器擴展?
uj5u.com熱心網友回復:
正如評論中提到的,常量運算式的規則通常不要求運算式中提到的每個變數及其生命周期在運算式評估之外開始constexpr。
有一個(很長的)要求串列,當不滿足時會阻止運算式成為常量運算式。只要沒有違反,運算式就是常量運算式。
使用的變數/物件的要求constexpr正式稱為可在常量運算式中使用的物件(盡管確切的定義包含更詳細的要求和例外,另請參見鏈接的 cppreference 頁面)。
查看串列,您可以看到僅在某些情況下才需要此屬性,即僅對于其生命周期在運算式之外開始的變數/物件,并且如果對其執行虛函式呼叫,則會執行左值到右值的轉換或者它是運算式中命名的參考變數。
這兩種情況都不適用于這里。不涉及虛函式,a也不是參考變數。通常,左值到右值的轉換會導致需求變得重要。每當您嘗試使用存盤在物件或其子物件之一中的值時,就會發生左值到右值的轉換。然而A,它是一個沒有任何狀態的空類,因此沒有可讀取的值。傳遞a給函式時,會呼叫隱式復制建構式來構造 的引數f,但由于類為空,實際上并沒有做任何事情。它不訪問任何狀態a。
請注意,如上所述,如果您使用參考,則規則會更嚴格,例如
A a;
A& ar = a;
constexpr int kInt = f(ar);
將失敗,因為ar命名了一個在常量運算式中不可用的參考變數。這將有望很快得到解決,以更加一致。(見https://github.com/cplusplus/papers/issues/973)
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/448843.html
