Сужение преобразования в паре с компиляцией с принудительным инициализатором, если второй атрибут не был скопирован-инициализирован
Так как С++ 11, сужение преобразования не разрешено в инициализации списка (включая агрегатную инициализацию), Итак, в основном:
char c{1000}; // Does not compile with g++, clang, vc
Но:
std::pair<char, double> p{1000, 1.0};
Скомпилируется со всем компилятором?
Но:
std::pair<char, double> p{1000, {1.0}};
Не компилируется с VC (ошибка C2398), дает предупреждение с clang и компилируется молча с g++...
Я бы ожидал поведения VC всюду, т.е. недопустимое сужение конверсии, забрасывающее ошибку. Какой компилятор прав?
С другой стороны, ни одна из объявлений переменных в следующих фрагментах не компилируется:
struct X {
char c;
double d;
};
X x1{999, 1.0};
X x2{999, {1.0}};
struct Y {
char c;
double d;
Y (char c, double d) : c(c), d(d) { }
};
Y y1{999, 1.0};
Y y2{999, {1.0}};
Итак, одно из моих предположений может заключаться в том, что есть что-то особенное в std::pair
? Что-то, что также сузило бы инициализацию с привязкой?
Ответы
Ответ 1
-
std::pair<char, double> p{1000, 1.0};
не диагностируется, потому что он вызывает конструктор template<class U1, class U2> pair(U1&&, U2&&)
(с U1 == int
и U2 == double
), который является точным совпадением; сужение не происходит, пока вы не попадете в тело конструктора.
-
std::pair<char, double> p{1000, {1.0}};
не может вызывать этот конструктор, потому что бит-init-list {1.0}
является не выводимым контекстом, поэтому вы не можете вывести U2
.
- В clang/libС++ он вызывает конструктор
pair(const T1&, const T2&)
; однако clang, по-видимому, не рассматривает преобразование, необходимое для создания временного связывания ссылок, как часть проверки сужения. Вероятно, это ошибка.
- GCC/libstdС++
pair
имеет шаблон конструктора template<class U1> pair(U1&&, const T2&)
, который лучше подходит. С этим конструктором второй аргумент не сужается, и первый аргумент является точным совпадением, поэтому вы не получаете никаких ошибок или предупреждений.