Ответ 1
Я полагаю, что фокус фокусника здесь является копией S
. Вы пропустили его, поэтому для вас генерируется дефолтный. Теперь это тоже функция constexpr
.
[class.copy.ctor] (emphasis mine)
12 Конструктор копирования/перемещения, который по умолчанию не определен как удаленный неявно определяется, когда он используется odr ([basic.def.odr]), когда это необходимо для постоянной оценки ([expr.const]) или когда явно по умолчанию после его первого объявления. [ Обратите внимание Конструктор копирования/перемещения определяется неявно, даже если реализация исключил его использование odr ([basic.def.odr], [class.teven]). - конец примечания] Если неявно определенный конструктор будет удовлетворять требованиям конструктора constexpr ([dcl.constexpr]), неявно определенный конструктор - constexpr.
Не попала ли оценка копии какой-либо из точек в [expr.const]/4? Это не. Он не выполняет преобразование lvalue в rvalue ни на одном из членов аргумента (нет ни одного, с кем можно выполнить преобразование). Он не использует свой параметр ссылки никоим образом, который потребует использования указанной ссылки в константном выражении. Таким образом, мы действительно получаем правильное константное выражение, хотя и неинтуитивное.
Мы можем проверить вышеизложенное, просто добавив участника в S
.
struct S
{
int a = 1;
constexpr S(int a) {}
};
Теперь копия c'tor пытается получить доступ к объекту, который нельзя использовать в константном выражении, как часть его оценки (по указанной ссылке). Таким образом, компиляторы будут жаловаться.