2016-04-25 10 views
19

:ブレース-INIT-リストの初期リスト内コンストラクタに適用するときに、括弧内のイニシャライザリストにシーケンスポイントがありますか? n4296のC++標準の文書によれば

[dcl.init.list](8.5.4.4)(pg223-224)

、パック拡張の結果である (14.5.3)を含む 初期化子節は、表示される順に評価されます。すなわち、 すべての値計算および指定された initializer-clauseに関連するすべての値の計算および副作用は、すべての値計算の前に順序付けされ、 副作用は のイニシャライザリストのコンマで区切られたリストに続く。 [注:この の評価順序は、 初期化のセマンティクスに関係なく保持されます。たとえば、 のinitializer-listの要素が、コンストラクタ呼び出しの引数として解釈されるときに適用されます( )。通常は、呼び出しの引数には配列制約がありません。末端ノート]

(強調鉱山)

ノートがここに追加されました:

#include <iostream> 

struct MyType { 
    MyType(int i, int j, int k, int l) 
    : sum(i + j + k + l) 
    { 

    } 

    int sum; 
}; 

int main() 
{ 
    int i = 0; 
    std::cout << MyType{ ++i, ++i, ++i, ++i }.sum << '\n'; 
} 

「10を印刷する必要があります:http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1030

これは、次のコードは、と私に読み込みます"

これは私の推論です:

  • がMyTypeが
  • ブレース-INIT-リストは順番
  • それはの引数として を解釈しても
  • で評価されているブレース-INIT-リストを経由して初期化されていますコンストラクタ呼び出しは
  • これは、それが(1,2,3,4)
がMyTypeとして評価されるべきであることを意味し

#include <initializer_list> 
#include <iostream> 

int main() 
{ 
    int i = 0; 
    std::initializer_list<int> il{++i, ++i, ++i, ++i}; 
    std::cout << *il.begin() + *(il.begin() + 1) + *(il.begin() + 2) + *(il.begin() + 3) << '\n'; 
} 

しかし、それはない:上記のコードは、まさにこのコードのように振る舞うべき、と言うことです10

。最初の例印刷物16「」と第2の例のプリント「10」

私は版画「16」に私の手を得ることができ、すべてのベンダーから文字通りすべてのコンパイラ、一見標準のその部分を無視し、配列を挿入することではありませんポイント。

私はここで何が欠けていますか?

注:以下は、この質問に関連すると思われる。

+0

試したコンパイラはどれですか? –

+0

gccのバージョン5.3.0(i686-posix-dwarf-rev0、MinGW-W64プロジェクトで構築された) –

+1

N4296は「標準」ではなく、C++ 17の標準化プロセスの作業草案です。 –

答えて

0

このノートでは、評価の順序とは関係ありません。コメントの1つに記載されているように、実際のパラメータを右辺値に変換する順番であり、標準ではそのような順序は定義されていません。私は、引数の評価は、{}で動作し、()方法を示すために、わずかにプログラムを修正

17:58: warning: operation on 'i' may be undefined [-Wsequence-point] 

: 次の警告(GCC)を受けるべきです。

このような変更を行うと、プログラムは左辺値を右辺値に変換する順序に依存しないため、あなたを失望させる曖昧さはありません。

#include <iostream> 

struct MyType { 
    MyType(int i, int j) 
    : sum(i + j) 
    { 

    } 

    int sum; 
}; 

int main() 
{ 
    int i = 0; 
    int a,b; 
    std::cout << MyType{ (a = ++i), (b = ++i) }.sum << '\n'; 
    std::cout << "Here clauses are evaluated in order they appear: a=" << a << ", b=" << b << std::endl; 
    i = 0; 
    std::cout << MyType((a = ++i), (b = ++i)).sum << '\n'; 
    std::cout << "Here order of evaluation depends on implementation: a=" << a << ", b=" << b << std::endl; 
} 

と打ち鳴らすとgccのために、このプログラムの出力:

打ち鳴らす:

3 
Here clauses are evaluated in order they appear: a=1, b=2 
3 
Here order of evaluation depends on implementation: a=1, b=2 

GCC:カーリーの場合

3 
Here clauses are evaluated in order they appear: a=1, b=2 
3 
Here order of evaluation depends on implementation: a=2, b=1 

あなたが見ることができるように、角括弧は、両方のコンパイラでの出現順に評価されます。産卵する。

+0

いいえ、質問は具体的にはシーケンスポイントについてであり、評価の順序に関するものではありません。 – lefticus

+0

あなたは「これはMyType(1,2,3,4)として評価されるべきであることを意味します。はい、それはそのように評価されますが、コンストラクタはその評価の後、MyType(i、i、i、i)として呼び出されます。また、コンストラクター呼び出しは、指定した注釈には記述されていません。評価では定義された順序付けしかありません。したがって、上記のようなコンパイル警告があります。 –

+0

"Note:この評価の順序は、初期化のセマンティクスに関係なく保持されます。たとえば、initializer-listの要素がコンストラクタ呼び出しの引数として解釈されるときに適用されます。呼び出しの引数の順序付けの制約 - "作成者呼び出し"を明示する元の投稿の部分.end note "部分。 – lefticus

3

答えははい、これはGCCとMSVCの両方のバグです。

これは、この問題のステータスです:

  1. のinit-リストルールに関してGCCに対して、いくつかのバグがあります。彼らのほとんどはGCCチームによって完全に承認されていません。これは少なくとも、問題が無効として閉じられていないため、ここにG ++にバグがあることを意味します。
  2. 私はMSVCコンパイラチームから実際にコンパイラのバグであり、 。しかし、私は指摘する外部バグはありません。 MSVC 2015 Update 3以降、古い動作が残っています。
  3. この時点で、最も賢明な標準準拠のコンパイラであるClangは、標準が読んでいるように実装しています。

私の個人的な調査、会議でのC++の専門家との議論、と私は、コンパイラの開発者から受け取った非公式の答えは、これはMSVCとGCCのバグであることを示しているが、私はいつもの自分の質問に答えるには消極的ですスタックオーバーフロー。しかしここにいるのです。

関連する問題