以下はコンパイルに失敗しますclang35 -std=c++11
:
#include <iostream>
#include <string>
#include <initializer_list>
class A
{
public:
A(int, bool) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
A(int, double) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
A(std::initializer_list<int>) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
};
int main()
{
A a1 = {1, 1.0};
return 0;
}
エラーあり
init.cpp:15:14: error: type 'double' cannot be narrowed to 'int' in initializer list [-Wc++11-narrowing]
A a1 = {1, 1.0};
^~~
init.cpp:15:14: note: insert an explicit cast to silence this issue
A a1 = {1, 1.0};
^~~
static_cast<int>( )
OTOH、縮小について警告し、コンパイルしますg++48 -std=c++11
init.cpp: In function ‘int main()’:
init.cpp:15:17: warning: narrowing conversion of ‘1.0e+0’ from ‘double’ to ‘int’ inside { } [-Wnarrowing]
A a1 = {1, 1.0};
^
init.cpp:15:17: warning: narrowing conversion of ‘1.0e+0’ from ‘double’ to ‘int’ inside { } [-Wnarrowing]
結果を生成します
A::A(std::initializer_list<int>)
どちらの動作も理にかなっていますか? cppreferenceからの引用
std::initializer_list を唯一の引数として、または残りの引数にデフォルト値がある場合は最初の引数として取るすべてのコンストラクターが調べられ、型 std::initializer_list の単一の引数に対するオーバーロード解決によって照合されます。
前の段階で一致が生成されない場合、T のすべてのコンストラクターは、braced-init-list の要素で構成される引数のセットに対するオーバーロードの解決に参加します。ただし、非縮小変換のみが許可されるという制限があります。この段階で、copy-list-initialization に最適な明示的なコンストラクターが生成される場合、コンパイルは失敗します (単純な copy-initialization では、明示的なコンストラクターはまったく考慮されないことに注意してください)。
A(std::initializer_list<int>)
縮小変換は許可されていないため、オーバーロード解決ステップがコンストラクターと一致せず、代わりにコンストラクターと一致すると予想されA(int, double)
ます。たとえば、andと printの両方でコンパイルするように変更A(std::initializer_list<int>)
すると、A(std::initializer_list<std::string>)
clang35
g++48
A::A(int, double)
予想通り。