c++ 在下標時是否必須使用一個const expr陣列?
struct A { static constexpr int a[3] = {1,2,3}; }; int main () { int a = A::a[0]; int b[A::a[1]]; }
是A :: a必須ofollow,noindex" target="_blank"> odr-used 在int a = A :: a [0]?
注意:這個問題代表了a debate in the Lounge 不太有趣/不合邏輯/無止盡的版本.
首先使用A :: a:
int a = A::a[0];
初始化器是一個常量表達式,但這並不能阻止A :: a在這裡被使用.而且,這個表示式使用的是A :: a.
從表示式A :: a [0]開始,我們來看看[basic.def.odr](3.2)/ 3(對於未來的讀者來說,我使用N3936的措辭):
A variablex
[in our case,A::a
] whose name appears as a potentially-evaluated expression ex [in our case, theid-expression
A::a
] isodr-used
unless
-
applying the lvalue-to-rvalue conversion to
x
yields a constant expression [it does]that does not invoke any non-trivial functions [it does not] and,
-
if
x
is an object [it is],-
ex
is an element of the set ofpotential results of an expressione
, where either the lvalue-to-rvalue conversion is applied toe
, ore
is a discarded-value expression.
-
那麼,e的可能價值在哪裡?表示式的一組潛在結果是一組表示式的子表示式(可以通過閱讀[basic.def.odr](3.2)/ 2)來檢查這一點,所以我們只需要考慮哪個表示式是子表示式.那些是:
A::a A::a[0]
其中,lvalue-to-rvalue轉換不會立即應用於A :: a,所以我們只考慮A :: a [0]. Per [basic.def.odr](3.2)/ 2,A :: a [0]的潛在結果集是空的,所以這個表示式使用了A :: a.
現在,你可以說我們首先將A :: a [0]改寫成*(A :: a 0).但是這並沒有改變:e的可能值
A::a A::a + 0 (A::a + 0) *(A::a + 0)
其中,只有第四個具有應用於其的左值向右值轉換,而[basic.def.odr](3.2)/ 2則表示*(A :: a 0)的潛在結果集是空.特別地,注意,陣列到指標的衰減不是一個左值轉換([conv.lval](4.1)),儘管它將一個數組的值轉換成一個指標rvalue– 它是一個數組 – 指標轉換([conv.array](4.2)).
第二次使用A :: a:
int b[A::a[1]];
這與第一種情況沒有區別,按照標準.再次,A :: a [1]是一個常量表達式,因此這是一個有效的陣列約束,但編譯器仍然允許在執行時發出程式碼來計算此值,並且陣列約束仍然是odr-使用A :: a .
請注意,常量表達式是(預設情況下)潛在評估的表示式. Per [basic.def.odr](3.2)/ 2:
An expression ispotentially evaluated unless it is an unevaluated operand (Clause 5) or a subexpression thereof.
[expr](5)/ 8只是重定向到其他子句:
In some contexts, unevaluated operands appear (5.2.8, 5.3.3, 5.3.7, 7.1.6.2). An unevaluated operand is not evaluated.
這些細節表示(分別)某些型別表示式的運算元,sizeof的運算元,noexcept的運算元以及decltype的運算元是未經評估的運算元.沒有其他型別的不確定的運算元.
程式碼日誌版權宣告:
翻譯自:http://stackoverflow.com/questions/23428684/is-a-constexpr-array-necessarily-odr-used-when-subscripted