19

次の C++11 プログラムは不正ですか?

const int x[] = {1,2,3};

static_assert(x[0] == 1, "yay");

int main() {}

gcc と clang はそう考えているようですが、なぜx[0] == 1定数式ではないのでしょうか?

x[0] == 1
subscript operator
*(x+0) == 1
array-to-pointer conversion (int* p = x)
*(p+0) == 1
pointer addition
*p == 1
indirection (lvalue y = x[0])
y == 1
lvalue-to-rvalue conversion:

整数の不揮発性 glvalue (はい、x[0] は glvalue であり、不揮発性です) (はい、型 const int を持ちます) または不揮発性 const オブジェクトを参照する列挙型 (はい、型 const int を持ちます)先行する初期化 (はい 1 で初期化)、定数式で初期化 (はい 1 は定数式)

確かに、x配列の最初の要素はこれらの条件を満たしています。

1 == 1

?

これはコンパイラのバグですか、標準的な欠陥ですか、それとも何か不足していますか?

5.19 [expr.const] のどの部分で、これは定数式ではないと述べていますか?

4

2 に答える 2

11

5.19 では:

[...]式は、次のいずれかを含まない限り定数式です[...]:

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

    • 定数式で初期化された、前に初期化された不揮発性 const オブジェクトを参照する整数型または列挙型の glvalue、または
    • constexpr で定義された不揮発性オブジェクトを参照する、またはそのようなオブジェクトのサブオブジェクトを参照するリテラル型の glvalue、または
    • 定数式で初期化された非揮発性一時オブジェクトを参照するリテラル型の glvalue

簡単に言うと、左辺値から右辺値への変換は、次の場合にのみ定数式で実行できます。

  • 定数で初期化された定数積分 (または列挙) 宣言: const int x = 3;
  • constexpr:を使用した宣言constexpr int x[] = {1,2,3};
  • 定数式で初期化された一時オブジェクト...

あなたの例には左辺値から右辺値への変換が含まれていますが、これらの例外xがないため、定数式ではありません。ただし、次のように変更した場合:

constexpr int x[] = {1,2,3};

static_assert(x[0] == 1, "yay");

int main() {}

その後、すべてが順調です。

于 2013-09-19T19:53:27.457 に答える
4

標準の現在の文言では、これはコンパイラのバグであり、プログラムは整形式です。実装が難しいため、標準不具合とするか検討中です。

詳細な説明については、次を参照してください。

https://groups.google.com/a/isocpp.org/forum/?fromgroups#!topic/std-discussion/Nv5_2dCHm6M

以下にコピーしたレポート:

N3690 までの C++11 公式の現在の文言には、次のようなものがあります。

条件式 e は、e の評価が次の式のいずれかを評価しない限り、コア定数式です。

  • 適用されない限り、左辺値から右辺値への変換 (4.1)
    • 定数式で初期化された、前に初期化された不揮発性 const オブジェクトを参照する整数型または列挙型の不揮発性 glvalue

グローバル スコープでの次の宣言:

const int x[2] = {42, 43};

でリスト初期化された 2 つの const int オブジェクトの配列を定義します{42, 43}

8.5.1 [dcl.init.aggr]/2:

8.5.4 で指定されているように、初期化子リストによって集合体が初期化されると、初期化子リストの要素は、添え字またはメンバーの昇順で、集合体のメンバーの初期化子として取得されます。

したがって、最初の要素オブジェクト42の初期化子は であり、2 番目の要素オブジェクトの初期化子は です43

*xは左辺値であり、コア定数式です。これには、配列からポインターへの変換とインダイレクションが伴いますが、どちらもコア定数式としての式を不適格とはしません。glvalue 式は、 の最初の要素オブジェクトを参照しますx*x整数型 (const int) の不揮発性 glvalue であり、前に初期化された不揮発性 const オブジェクトを参照し、定数式 で初期化されます42

したがって、glvalue に適用される左辺値から右辺値への変換*x は、定数式で許可されているため、次の形式は整形式です。

constexpr int y = *x;

gcc も clang トランクも現在、これを定数式として受け入れていませんが、標準に従って整形されています。

これは意図したものですか?

完全なデモ プログラム:

const int x[2] = {42, 43};
constexpr int y = *x;
int main() {}

実装は、同等の左辺値でも同様に失敗しx[0]ます。

于 2013-09-20T11:39:06.890 に答える