Ответ 1
Вы столкнулись с ситуацией, которая была решена с помощью разрешения Основной вопрос 1467 сразу после завершения С++ 14.
Пусть сначала отметим, что класс foo
является агрегатом. Ваш код выполняет инициализацию прямого списка для foo
. Правила для инициализации списка приведены в [8.5.4p3].
В С++ 14 (цитируя из N4140, рабочий проект, ближайший к опубликованному стандарту), вышеприведенный параграф начинался с:
Определяется список-инициализация объекта или ссылки типа
T
следующим образом:
- Если
T
является агрегатом, выполняется агрегатная инициализация (8.5.1).[...]
Итак, если ваш класс является агрегатом, компилятор пытается выполнить агрегатную инициализацию, которая не выполняется.
Это было признано проблемой и зафиксировано в рабочем проекте. Цитируя из текущей версии N4527, вышеупомянутый пункт теперь начинается с:
Определяется список-инициализация объекта или ссылки типа
T
следующим образом:
- Если
T
- тип класса, а в списке инициализаций есть один элемент типа cvU
, гдеU
естьT
или класс, полученный изT
, объект инициализируется из этого элемента (путем инициализации копирования для инициализация списка копий или прямая инициализация для прямой список инициализации).- В противном случае, если
T
- это массив символов, а в списке инициализаций есть один элемент, который является соответствующим образом типизированным строковым литералом (8.5.2), инициализация выполняется, как описано в этом разделе.- В противном случае, если
T
является агрегатом, выполняется агрегатная инициализация (8.5.1).[...]
Ваш пример теперь относится к случаю, описанному первой точкой маркера, и foo
инициализируется прямым списком с использованием конструктора копии по умолчанию (независимо от того, является ли он explicit
, поскольку он имеет прямую инициализацию).
То есть... если компилятор реализует разрешение в отчете о дефектах.
- GCC 5.2.0 (и 6.0.0 trunk), похоже, делает это, но, похоже, имеет ошибку, связанную с этим
explicit
. - Clang 3.6.0 не делает, но 3.8.0 trunk делает, и делает это правильно (
explicit
не имеет значения). - MSVC 14 делает, но IntelliSense в среде IDE не работает (squiggles под
bar
- похоже, что компилятор EDG, используемый IntelliSense, также не обновлялся).
Обновление. Поскольку этот ответ был написан, рабочий проект был дополнительно изменен несколькими способами, которые имеют отношение к примеру в вопросе и объяснению выше:
- CWG 2137 указывает, что первая пуля в приведенном выше параграфе слишком сильно зашла, применив это исключение ко всем типам классов примечания к выпуску содержат соответствующий пример). Начало пули теперь гласит:
- Если
T
- это совокупный класс и [...]
- Если
- Разрешение CWG 1518, содержащееся в документе P0398R0 указывает, что классы, объявляющие конструктор
explicit
(даже по умолчанию), больше не являются агрегатами.
Это не меняет того факта, что после того, как все изменения будут реализованы, пример в вопросе предназначен для работы с или без explicit
; просто стоит знать, что основные механизмы, которые делают его работу, немного изменились.
Обратите внимание, что все эти изменения являются разрешениями отчетов о дефектах, поэтому они должны применяться, когда компиляторы также находятся в режимах С++ 14 и С++ 11.