Первый код, то, что я думаю, должно произойти. (В дальнейшем я проигнорирую первый параметр, так как нас интересует только второй параметр, первый из которых всегда является точным совпадением в вашем примере). Обратите внимание, что в настоящее время правила применяются в спецификации, поэтому я бы не сказал, что у одного или другого компилятора есть ошибка.
B1 b1a(x, {y});
Этот код не может вызвать const Y&
конструктора в C++ 11, потому что Y
представляет собой совокупность и Y
не имеет элемента данных типа Y
(конечно) или что-то еще initializable ею (это что-то некрасиво, и он исправляется - на компакт-диске C++ 14 пока нет формулировки, поэтому я не уверен, будет ли в последнем C++ 14 это исправление).
Конструктор с параметром const A<Y>&
можно назвать - {y}
будет принят в качестве аргумента конструктора A<Y>
и инициализирует этот конструктор-х std::initializer_list<Y>
.
Следовательно - Второй конструктор успешно вызван.
B1 b1b(x, {{y}});
Здесь в основном тот же аргумент имеет значение счетчиков для конструктора с параметром const Y&
.
Для конструктора с параметром типа const A<Y>&
это немного сложнее. Правило для стоимости преобразования при вычислении перегрузки вычисляет стоимость инициализации std::initializer_list<T>
, чтобы каждый элемент скобочного списка был конвертирован в T
. Однако ранее мы говорили, что {y}
не может быть преобразован в Y
(так как это совокупность). Теперь важно знать, является ли std::initializer_list<T>
агрегатом или нет. Честно говоря, у меня нет идеи, следует ли это считать агрегатом в соответствии со стандартными библиотечными предложениями.
Если мы возьмем его как неагрегат, тогда мы рассмотрим конструктор копирования std::initializer_list<Y>
, который, однако, повторит ту же последовательность тестов (что приведет к «бесконечной рекурсии» при проверке разрешения перегрузки).Поскольку это довольно странно и нереализуемо, я не думаю, что какая-либо реализация принимает этот путь.
Если мы возьмем std::initializer_list
, чтобы быть агрегатом, мы будем говорить «нет, конверсия не найдена» (см. Вышеуказанные проблемы с агрегатами). В этом случае, поскольку мы не можем вызвать конструктор инициализатора с единственным списком инициализаторов в целом, {{y}}
будет разделен на несколько аргументов, а конструктор (ы) A<Y>
будет брать каждый из них отдельно. Следовательно, в этом случае мы получим {y}
, инициализируя std::initializer_list<Y>
как единственный параметр, который отлично работает и работает как шарм.
Таким образом, в предположении, что std::initializer_list<T>
является агрегатом, это нормально, и второй конструктор успешно завершил.
B2 b2a(x, {P<Y>(y)});
В этом случае и в следующем случае, мы не имеем совокупный вопрос, как и выше с Y
больше, поскольку P<Y>
имеет предоставленный пользователем конструктор.
Для конструктора параметров P<Y>
этот параметр будет инициализирован {P<Y> object}
. Поскольку P<Y>
не имеет списков инициализаторов, список будет разбит на отдельные аргументы и вызовет конструктор перемещения P<Y>
с объектом rvalue P<Y>
.
Для конструктора параметра A<P<Y>>
, это то же самое, как выше случае с A<Y>
инициализированного {y}
: Так как std::initializer_list<P<Y>>
может быть инициализирован {P<Y> object}
, список аргументов не расщепляется, и, следовательно, скобки используются для инициализатора, что конструктор'S std::initializer_list<T>
,
Теперь оба конструктора работают нормально. Они действуют как перегруженные функции здесь, а их второй параметр в обоих случаях требует определенного пользователем преобразования. Определенные пользователем последовательности преобразования могут сравниваться только в том случае, если в обоих случаях используется одна и та же функция преобразования или конструктор - здесь не так. Следовательно, это неоднозначно в C++ 11 (и на компакт-диске C++ 14).
Обратите внимание, что здесь мы имеем тонкий момент, чтобы исследовать
struct X { operator int(); X(){/*nonaggregate*/} };
void f(X);
void f(int);
int main() {
X x;
f({x}); // ambiguity!
f(x); // OK, calls first f
}
Этого счетчик интуитивный результат, вероятно, будет зафиксирован в той же перспективе с фиксацией агрегированных инициализации странности, упомянутой выше (оба будет называть первую е) , Это реализовано тем, что {x}->X
становится преобразованием идентичности (как и X->x
). В настоящее время это пользовательское преобразование.
Итак, неопределенность здесь.
B2 b2b(x, {{P<Y>(y)}});
Для конструктора с параметром const P<Y>&
, мы снова расколоть аргументы и получить {P<Y> object}
аргумент, передаваемый в конструктор (ы) P<Y>
. Помните, что у P<Y>
есть конструктор копирования. Но усложнение здесь заключается в том, что нам не разрешено использовать его (см. 13.3.3.1p4), поскольку для этого потребуется преобразование, определяемое пользователем. Единственный конструктор слева - тот, который принимает Y
, но Y
не может быть инициализирован {P<Y> object}
.
Для конструктора с параметром A<P<Y>>
, то {{P<Y> object}}
может инициализировать std::initializer_list<P<Y>>
, потому что {P<Y> object}
конвертируется в P<Y>
(иначе, чем с Y
выше - Dang, агрегатов).
Итак, второй конструктор, получивший название.
Резюме для всех 4
- второй конструктор называется успешно
- в предположении, что
std::initializer_list<T>
представляет собой совокупность, это прекрасно и называют второй конструктор успешно
- двусмысленность здесь
- второй конструктор называется успешно
Два локальных переменных с именем «» b2b в функции «F» это просто опечатка и не является причиной проблемы, я полагаю ... – astraujums
Действительно! Исправлено ... –
Мне кажется, что создание 'A' из initializer_list и' P' из 'T' должно быть точным совпадением, следовательно, двусмысленностью. Я не могу объяснить, почему компиляторы выбирают разные, чтобы жаловаться. –