MSVC не учитывает оператор преобразования при инициализации агрегата с круглыми скобкамиC++

Программы на C++. Форум разработчиков
Ответить
Anonymous
 MSVC не учитывает оператор преобразования при инициализации агрегата с круглыми скобками

Сообщение Anonymous »

Я наткнулся на этот код:

Код: Выделить всё

struct type1 { int a; };
struct type2 { int a; type1 agg; int b; };

struct deducer {
operator type1() {
return type1{};
}
};

auto main() -> int {
type2 a{0, deducer{}, 0}; // fine
type2 b(0, deducer{}, 0); // error on msvc
}
https://godbolt.org/z/5d5ao6coa
Clang и GCC компилируют его правильно, а MSVC нет.
Мне кажется, что MSVC неверен, поскольку инициализация с круглыми скобками должна быть почти эквивалентна вызову функции-конструктора.
Я пытался найти соответствующий параграф в стандарте, но я не совсем уверен в этом допустимость.
Из [dcl.init]/16.6.2.2:

В противном случае, если ни один конструктор не является жизнеспособным, типом назначения является агрегатный класс, а инициализатором является список-выражений в скобках, объект инициализируется следующим образом.
Пусть e1, …, en — элементы агрегата ([dcl.init.aggr]).
Пусть x1, …, xk — элементы списка-выражений.
Если k больше, чем n, программа имеет неверный формат.
/>Элемент ei инициализируется копированием с помощью xi для 1  ≤ i  ≤ k.
Остальные элементы инициализируются с помощью своих инициализаторов элементов по умолчанию, если таковые имеются, а в противном случае инициализируются значением.
Для каждого 1 ≤ i < j ≤ n, каждое вычисление значения и побочный эффект, связанные с инициализацией ei, располагаются перед теми, которые связаны с инициализацией ej.

Из этого правила мы затем получаем [dcl.init]/16.6.3

В противном случае (т. е. для остальных случаев инициализации копирования) определяемые пользователем преобразования, которые могут преобразовать исходный тип в целевой тип или (когда используется функция преобразования) в его производный класс, перечисляются, как описано в [over.match.copy], и лучшее из них выбирается посредством разрешения перегрузки ([over.match]). Если преобразование невозможно выполнить или оно неоднозначно, инициализация имеет неверный формат. Выбранная функция вызывается с выражением инициализатора в качестве аргумента; если функция является конструктором, вызов представляет собой prvalue неквалифицированной cv версии целевого типа, результирующий объект которого инициализируется конструктором. Вызов используется для прямой инициализации, в соответствии с приведенными выше правилами, объекта, который является местом назначения инициализации копирования.

Это будет означать, что преобразование, определяемое пользователем, должно быть разрешено.

Теперь вопросы:
  • Правен ли MSVC или правы GCC и Clang?
  • Подходит ли абзац из найденного мной стандарта для описания того, почему пользовательское преобразование должно быть разрешено при инициализации агрегатов в скобках?
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C++»