9

初期化子リストコンストラクターの使用法について、次の例を検討してください。

std::vector<std::string> v = { "xyzzy", "plugh", "abracadabra" };
std::vector<std::string> v({ "xyzzy", "plugh", "abracadabra" });
std::vector<std::string> v{ "xyzzy", "plugh", "abracadabra" }; 

それらの間に(わずかでも)違いはありますか?

大規模なプロジェクトで標準を定義する必要がある場合、どのスタイルを選択しますか?
私は最初のスタイルを好みます。また、最初のスタイルは他のプログラミング言語になじみがあるように見えます。

4

1 に答える 1

7

avectorstrings の場合、3 つの形式に違いはありません。initializer_listただし、を受け取るコンストラクターがisの場合、最初の 2 つと他の 2 つの間に違いが生じる可能性がありexplicitます。その場合、最初のcopy-list-initializationは許可されませんが、他の 2 つのdirect-list-initializationは許可されます。

そういうわけで、私の好みは第三形態でしょう。括弧が冗長なので、2 番目は避けます。


Yakk がコメントで指摘しているように、構築される型に を受け取るコンストラクターがない場合、さらなる違いが生じinitializer_listます。

たとえば、構築される型には、コンストラクターchar const *の代わりに、すべて type の 3 つの引数を取るコンストラクターがあるとしますinitializer_list。その場合、フォーム 1 と 3 は有効ですが、2 は形式が正しくありません。括弧で囲まれた場合、braced-init-list が 3 つの引数コンストラクターと一致しないためです。

型に初期化子リスト コンストラクターがあるが、波括弧初期化リストの要素が暗黙的に に変換できないinitializer_list<T>場合、他のコンストラクターが考慮されます。一致する別のコンストラクターが存在すると仮定すると、フォーム 2 では中間コピーが構築されますが、他の 2 つのコンストラクターは構築されません。これは、 でコンパイルされた次の例で実証できます-fno-elide-constructors

struct foo
{
    foo(int, int) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
    foo(foo const&) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
    foo(std::initializer_list<std::string>) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
};

int main()
{
    foo f1 = {1,2};
    std::cout << "----\n";
    foo f2({1,2});
    std::cout << "----\n";
    foo f3{1,2};
}

出力:

foo::foo(int, int)
----
foo::foo(int, int)
foo::foo(const foo&)
----
foo::foo(int, int)


次のケースは質問の一部ではありませんが、それでも知っておくとよいでしょう。ネストされたブレースを使用すると、場合によっては直感的でない動作が発生する可能性があります。検討

std::vector<std::string> v1{{ "xyzzy", "plugh", "abracadabra" }};
std::vector<std::string> v2{{ "xyzzy", "plugh"}};

v1期待どおりに動作しvector、3 つの文字列を含むになりますがv2、未定義の動作が発生します。詳細な説明については、この回答を参照してください。

于 2014-08-04T14:48:02.847 に答える