33

つまり、なぜこれを行うのですか:

struct S {};

struct T
{
    T(S& s) : s{s} {}

    S& s;
};

int main()
{
    S s;
    T t{s};
}

GCC 4.7 でコンパイラ エラーが発生する場合:

test.cpp: In constructor 'T::T(S&)':
test.cpp:5:18: error: invalid initialization of non-const reference of type 'S&' from an rvalue of type '<brace-enclosed initializer list>'

?

エラーを修正するには、 を に変更する必要がありs{s}ますs(s)。これは、均一な初期化の均一性を壊しませんか?

編集:clangで試してみたところ、clangはそれを受け入れたので、おそらくGCCのバグですか?

4

3 に答える 3

23

はい、バグです。これは新しいもので、2012 年 2 月にワーキング ペーパーで投票されました (リンク)。

Nicol Bolasは、ワーキング ペーパーへの変更がその後に行われたため、gcc は実際には FDIS 承認の C++11 標準に準拠しているコンパイラであると指摘しています。

于 2012-05-09T04:22:52.947 に答える
9

コンパイラのエラーだと思います。リストの初期化による参照の初期化を扱う 2 つの段落は次のとおりです (n3337):

§8.5.4/3

型 T のオブジェクトまたは参照のリスト初期化は、次のように定義されます。

  • それ以外の場合、初期化子リストに型 E の単一の要素があり、T が参照型ではないか、その参照型が E に関連する参照である場合、オブジェクトまたは参照はその要素から初期化されます。要素を T に変換するために縮小変換 (以下を参照) が必要な場合、プログラムは不適切な形式です。

  • それ以外の場合、T が参照型の場合、T によって参照される型の一時的な prvalue はリスト初期化され、参照はその一時的なものにバインドされます。[ 注: いつものように、参照型が非 const 型への左辺値参照である場合、バインディングは失敗し、プログラムは不正な形式になります。— エンドノート]

コンパイラは、参照関連が次のように定義されているため、最初の段落を適用する必要があるときに、最後の段落を適用しているようです。

8.5.3/4

型「cv1 T1」および「cv2 T2」が与えられた場合、T1 が T2 と同じ型である場合、または T1 が T2 の基本クラスである場合、「cv1 T1」は「cv2 T2」に参照関連です。

質問の場合、brace-initialization-list 内の参照と初期化子の型はまったく同じです。これは、初期化が有効であることを意味します。


FDIS 草案では、同等の段落の順序が逆になっていました。これは、FDIS ドラフト (n3290) が*lvalue* のブレース リストの初期化を許可していなかったことを意味します。一方、テキストを読むと、それが標準のバグであり、意図が n3337 の順序を持​​っていたことは明らかです。

  • それ以外の場合、T が参照型の場合、T によって参照される型の一時的な prvalue はリスト初期化され、参照はその一時的なものにバインドされます。

  • それ以外の場合、イニシャライザ リストに単一の要素がある場合、オブジェクトまたは参照はその要素から初期化されます。要素を T に変換するために縮小変換 (以下を参照) が必要な場合、プログラムは不適切な形式です。

そのドキュメントの順序は、すべての参照型が最初の句で処理されるため、次の段落で参照に言及しても意味がないことを意味します。

于 2012-05-09T04:13:20.620 に答える