Действительно ли это двусмысленно?

Итак, я знаю, что фигурные скобки в коде могут означать больше, чем просто initializer_list: Что такое список, заключенный в фигурные скобки, если не список инициализаторов?< /а>

Но что они должны использовать по умолчанию?

Например, предположим, что я определяю перегруженную функцию:

void foo(const initializer_list<int>& row_vector) { cout << size(row_vector) << "x1 - FIRST\n"; }
void foo(const initializer_list<initializer_list<int>>& matrix) { cout << size(matrix) << 'x' << size(*begin(matrix)) << " - SECOND\n"; }

Если я позвоню foo({ 1, 2, 3 }), очевидно, будет вызван 1st. И если я позвоню foo({ { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }), очевидно, будет вызван 2nd.

Но что, если я позвоню:

foo({ { 1 }, { 2 }, { 3 } })

Являются ли эти вложенные скобки int-инициализаторами или initializer_list<int>-инициализаторами? gcc говорит, что это неоднозначно Но если вы возьмете этот код и запустите его на http://webcompiler.cloudapp.net/ Visual Studio говорит, что просто создает файл initializer_list<int>. Кто прав? Здесь должен быть дефолт?


person Jonathan Mee    schedule 05.08.2016    source источник
comment
Это двусмысленно, потому что я не знаю, что правильно. Если человек не может знать, какая надежда может быть у компилятора?   -  person Mooing Duck    schedule 05.08.2016
comment
И int i = {42};, и std::initializer_list<int> ini = { 42 }; верны Демо. Так что неоднозначно.   -  person Jarod42    schedule 05.08.2016
comment
@MooingDuck Вероятно, это мое заблуждение, но я думал, что помимо инициализации списка мы должны указать, какой тип мы инициализируем. Не просто сделать { 1 }, я думал, что мы должны сделать int{ 1 }. Если это так, Visual Studio кажется наиболее разумным.   -  person Jonathan Mee    schedule 05.08.2016
comment
@JonathanMee: Это не так, вам не нужно указывать тип. {{1}} может соответствовать init_list<int> или init_list<init_list<int>>, или даже std::array<char,1>, в зависимости от контекста.   -  person Mooing Duck    schedule 05.08.2016
comment
Например, @MooingDuck cout << { 1 } << endl является незаконным. Несмотря на то, что есть оператор вставки для ints. на мой взгляд, если вы прямо не указали тип, это не должен быть конструктор. Очевидно, что это делает инициализация, и, очевидно, int{ 1 } делает это, но { 1 }, на мой взгляд, не делает этого. Я думаю об этом как о initializer_list<int>.   -  person Jonathan Mee    schedule 05.08.2016
comment
Это незаконно не потому, что здесь нет преобразования, а потому, что грамматика не позволяет вам написать здесь список инициализации в фигурных скобках.   -  person T.C.    schedule 05.08.2016
comment
@Т.С. Это действительно помогает мне прояснить. Итак, вы говорите, что везде, где я мог бы инициализировать intializer_list<int>, я в равной степени имел бы право инициализировать int, и, поскольку нет предпочтительного преобразования, это неоднозначно.   -  person Jonathan Mee    schedule 05.08.2016
comment
@ Джонатан Нет, и это неправда.   -  person Barry    schedule 06.08.2016


Ответы (1)


Правило находится в [over.ics.list]:

В противном случае, если тип параметра std::initializer_list<X> и все элементы списка инициализатора могут быть неявно преобразованы в X, последовательность неявного преобразования является наихудшим преобразованием, необходимым для преобразования элемента списка в X, или если в списке инициализатора нет элементов , преобразование личности.

В обеих ваших перегрузках наихудшим необходимым преобразованием является преобразование идентификатора. Таким образом, у нас есть две неявные последовательности преобразования с одинаковым рангом. В [over.match.best] есть правило, которое предпочитает инициализацию списка std::initializer_list<X> альтернативам (поэтому std::initializer_list<int> предпочтительнее int для {1}), но ничто не указывает на то, что это правило должно применяться рекурсивно.

Поскольку нет ничего, что могло бы устранить неоднозначность двух последовательностей преобразования, вызов неоднозначен. gcc и clang правильно отвергать.

person Barry    schedule 05.08.2016
comment
Мне любопытно, решила ли MS, что, поскольку в ней не указано, применяется ли правило рекурсивно, было бы безопаснее относиться к нему как к таковому, если и до тех пор, пока не будет указано иное, или если они просто что-то испортили. - person Justin Time - Reinstate Monica; 05.08.2016
comment
Я думаю, что это требует решения CWG, поскольку рекурсивное применение этого правила кажется более полезным. - person bogdan; 06.08.2016
comment
@bogdan Я опубликовал об этом. Люди кажутся оправданно более заинтересованными в enable_shared_from_this :) - person Barry; 09.08.2016