avector
のstring
s の場合、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
、未定義の動作が発生します。詳細な説明については、この回答を参照してください。