Ответ 1
Похоже, что clang полагается на формулировку pre С++ 17 из раздела С++ 14 [class.inhctor] p3:
Для каждого конструктора без шаблона в наборе кандидатов унаследованных конструкторов, отличных от конструктора, не имеющего параметров или конструктора копирования/перемещения, имеющего единственный параметр, конструктор неявно объявляется с теми же характеристиками конструктора, если не существует конструктор, объявленный пользователем, с та же подпись в полном классе, где появляется объявление using, или конструктор будет по умолчанию, копирует или перемещает конструктор для этого класса. Аналогично, для каждого шаблона конструктора в наборе кандидатов наследуемых конструкторов шаблон конструктора неявно объявляется с теми же характеристиками конструктора, если в полном классе не существует эквивалентного объявленного пользователем шаблона конструктора ([temp.over.link]), где появляется декларация использования. [Примечание: аргументы по умолчанию не наследуются. Спецификация исключения подразумевается, как указано в [except.spec]. - конечная нота]
Итак, в С++ 14:
using Foo::Foo;
означает, что Bar
не наследует конструктор по умолчанию Foo
и Bar
не имеет конструктора по умолчанию, поскольку он запрещен вашим выражением:
constexpr Bar(Foo const obj) noexcept : Foo(obj) {}
Добавление конструктора по умолчанию в Bar
устраняет проблему, см. Его в прямом эфире:
constexpr Bar() = default ;
Формулировка была изменена в С++ 17 на бумагу p0136r1: Наследование наследовательных конструкторов (основная проблема 1941 и др.), Которая была видна, была принята из изменений между С++ 14 и С++ 17 DIS
Следующие документы были перенесены на заседания комитетов, но их содержание слишком специфично, чтобы вызывать отдельные функции: N3922, N4089, N4258, N4261, N4268, N4277, N4285, P0017R1, P0031R0, P0033R1, P0074R0, P0136R1, P0250R3, P0270R3, P0283R2, P0296R2, P0418R2, P0503R0, P0509R1, P0513R0, P0516R0, P0517R0, P0558R1, P0599R1, P0607R0, P0612R0
мы можем удалить [class.inhctor]
:
Удалите 12.9 class.inhctor, "Наследование конструкторов".
Я не вижу никаких формулировок в p0136r1
которые больше ограничивали бы этот случай. В списке отчетов о дефектах конкретно не рассматривается этот случай, но изменения в формулировках кажутся непротиворечивыми.
Таким образом, похоже, что gcc здесь правильно, и у нас есть потенциальная ошибка clang.
Заметки о выпуске gcc 7
Мы также получаем диагностику в gcc pre 7.x(см. Ее в прямом эфире). Если мы посмотрим на примечания к выпуску gcc 7, мы увидим:
Семантика по умолчанию унаследованных конструкторов изменилась во всех режимах, следующих за P0136. По сути, разрешение перегрузки происходит так, как если бы вызывал наследуемый конструктор напрямую, а компилятор заполнял строительство других баз и элементов по мере необходимости. В большинстве применений не должно быть никаких изменений. Старое поведение можно восстановить с помощью -fno-new-inheriting-ctors или -fabi-version менее 11.
Кажется, что подтверждает первоначальный вывод. Если мы используем -fno-new-inheriting-ctors
со слегка измененной версией вашей программы, он больше не компилирует, который поддерживает это изменение с помощью P0136
.