31

N4527 5.20[expr.const]p5

定数式は、値が定数式 (以下で定義) の許可された結果であるエンティティを参照する glvalue コア定数式、または値がオブジェクトである prvalue コア定数式のいずれかです。 :

— 参照型の各非静的データ メンバーは、定数式の許可された結果であるエンティティを参照します。

— オブジェクトまたはサブオブジェクトがポインター型の場合、静的ストレージ期間を持つオブジェクトのアドレス、そのようなオブジェクトの末尾を過ぎたアドレス (5.7)、関数のアドレス、または null ポインター値が含まれます。

エンティティは、それが一時オブジェクトではないか、値が上記の制約を満たす一時オブジェクトである静的ストレージ期間を持つオブジェクトである場合、または関数である場合、定数式の許可された結果です。

void foo(){
    int a = 1;
    int b[a || 1]{};//ok in gcc 5.1.0, error in clang 3.8.0
    static_assert(a || 1,"");//ok in gcc 5.1.0, error in clang 3.8.0
    switch(1){
        case a || 1://ok in gcc 5.1.0, error in clang 3.8.0
            ;
        }
}

a || 1定数ですか?


N4527 5.20[expr.const]p2

条件式 e は、抽象マシン (1.9) の規則に従って e を評価した場合に、次の式のいずれかが評価されない限り、コア定数式です。

(2.7) — 適用されない限り、左辺値から右辺値への変換 (4.1)

(2.7.1) — 定数式で初期化された、前に初期化された完全な不揮発性 const オブジェクトを参照する、整数型または列挙型の不揮発性 glvalue、または

(2.7.2) — 文字列リテラルのサブオブジェクトを参照する不揮発性の glvalue (2.13.5)、または

(2.7.3) — constexpr で定義された不揮発性オブジェクトを参照する、またはそのようなオブジェクトの可変でないサブオブジェクトを参照する、非揮発性の glvalue、または

(2.7.4) — 有効期間が e の評価内で始まる不揮発性オブジェクトを参照する、リテラル型の不揮発性 glvalue。

コア定数式ですかa || 1?

4

3 に答える 3

24

aは定数式ではないため (以下の標準的な引用を参照)、次のようになります。

a || 1 

も定数式ではありませんが、式が true と評価される必要があることはわかっていますが、標準ではここで左から右への評価が必要であり、コンパイラが の左辺値から右辺値への変換をスキップできる例外はありませんa

しかし:

const int a = 1;

からの例外に該当するため、定数式で使用できます5.20p2(強調鉱山):

適用されない限り、左辺値から右辺値への変換 (4.1)

  • 定数式で初期化された、前に初期化された完全な不揮発性 const オブジェクトを参照する整数型または列挙型の不揮発性 glvalue、または
  • 文字列リテラルのサブオブジェクトを参照する不揮発性の glvalue (2.13.5)、または
  • constexpr で定義された非揮発性オブジェクトを参照する、またはそのようなオブジェクトの可変でないサブオブジェクトを参照する非揮発性 glvalue、または
  • 有効期間が e の評価内で始まる不揮発性オブジェクトを参照する、リテラル型の不揮発性 glvalue

このルールは、例外が適用されないため、元のケースが定数式ではない理由でもあります。

おそらくgccこれを許可しています:

int b[a || 1]{};

を使用して警告を表示する必要がありますが、拡張子として可変長配列として-pedantic. それは static_assert のケースを説明するものではありませんが、それらは定数の折りたたみである可能性がありますが、as-if ルールでは定数式と見なすことはできないと思います。

更新、可能性のある gcc 拡張

このバグレポートから、論理演算子の RHS は LHS を定数式で未評価にする可能性があります。これは gcc 拡張の可能性があるようです:

これは、定数式で非定数オブジェクトを使用しているにもかかわらず、問題なくコンパイルされます。

int i;
static_assert( i || true, "" );
static_assert( ! ( i && false ), "" );

|| と仮定しているようです。と && は交換可能ですが、短絡は一方向にしか機能しません。

そして最後のコメントは次のように述べています。

これは意図的な言語拡張であり、スイッチを使用して無効にできると思います。static_assert が常に厳密であるとよいでしょう。

これは Is it a conforming compiler extension totreat non-constexpr standard library functions as constexpr? で-pedantic発行するのと同様のフラグを無駄に使用すると警告をトリガーする、非準拠の拡張機能のようです。.

C++11/C++14 引用

セクション5.205.19C++14 および C++11 のセクションです。ドラフト C++14 標準からの関連する引用は次のとおりです。

適用されない限り、左辺値から右辺値への変換 (4.1)

  • 定数式で初期化された、前に初期化された非揮発性 const オブジェクトを参照する整数または列挙型の非揮発性 glvalue [ 注: 文字列リテラル (2.14.5) は、そのようなオブジェクトの配列に対応します。—エンドノート]、または

  • constexpr で定義された非揮発性オブジェクトを参照する、またはそのようなオブジェクトの可変でないサブオブジェクトを参照する非揮発性 glvalue、または

  • 有効期間が e の評価内で始まる不揮発性オブジェクトを参照する、リテラル型の不揮発性 glvalue。

ドラフト C++11 標準の場合は次のとおりです。

適用されない限り、左辺値から右辺値への変換 (4.1)

  • 定数式で初期化された、前に初期化された不揮発性 const オブジェクトを参照する整数型または列挙型の glvalue、または

  • constexpr で定義された不揮発性オブジェクトを参照する、またはそのようなオブジェクトのサブオブジェクトを参照するリテラル型の glvalue、または

  • 定数式で初期化された、存続期間が終了していない不揮発性の一時オブジェクトを参照するリテラル型の glvalue。

于 2015-07-20T21:06:15.757 に答える
1

コンパイラが割り当てチェーン全体をチェックすると、"a || 1" が定数式であると判断できます。ただし、a は変数であるため、a が割り当てられていないことをコンパイラがチェックしない限り、"a || 1" が定数式であることを知る方法はありません。

于 2015-07-20T21:05:41.603 に答える