Если я что-то упустил, gcc и clang здесь верны.

ющий код принят GCC 7.2 и clang 5.0.0, но отклонен Microsoft VS 2017 15.5.0 Preview 5 и компилятором 19 Intel C ++:

struct S { };

constexpr int f(S)
{
    return 0;
}

int main()
{
    auto lambda = [](auto x)
    {
        constexpr int e = f(x);
    };

    lambda(S{});
}

Microsoft:

<source>(12): error C2131: expression did not evaluate to a constant

Intel:

<source>(12): error: expression must have a constant value
    constexpr int e = f(x);
                      ^
<source>(12): note: the value of parameter "x" (declared at line 10) cannot be used as a constant
    constexpr int e = f(x);
                        ^

Если я заменюf(x) с участиемf(decltype(x){})И Microsoft, и Intel не жалуются. Я это понимаюx не является константным выражением, но оно не используется внутриf, Вероятно, поэтому GCC и Clang не жалуются.

Я думаю, что компиляторы Microsoft и Intel правы, отвергая этот код. Как вы думаете?

 Evg07 дек. 2017 г., 15:03
@RichardHodges,-std=c++14.
 Evg07 дек. 2017 г., 15:11
@ W.F., Лямбда намеренно неconstexpr (в реальном коде это не так).
 Bob__07 дек. 2017 г., 15:44
MSVC также жалуется:«сбой был вызван чтением переменной за пределами ее времени жизни» и g ++ и clang сообщают о неиспользованной переменной. если тывернуть из лямбды они компилируются.
 W.F.07 дек. 2017 г., 15:05
Хорошо, теперь я думаю, что это ошибка в gcc и clang, так как c ++ 14 не поставляется с constexpr lambda ... это доступно с c ++ 17
 Evg08 дек. 2017 г., 09:05
@Bob__f(x) следует использовать в контексте, где требуется постоянное выражение. Когда вы делаетеreturn f(x)Вы не форсируете оценкуf(x) во время компиляции.

Ответы на вопрос(2)

о в C ++ 11 с помощью функции шаблона:

template <typename T>
void foo(T x)
{
    constexpr int e = f(x);
}

int main()
{
    foo(S{});
}

на godbolt.org

Вопрос, учитывая ...

template <typename T>
void foo(T x)
{
    constexpr int e = f(x);
}

...являетсяf(x) постоянное выражение?

Из[Expr.const]:

Выражениеe этовыражение основной константы если оценкаeСледуя правилам абстрактной машины, оценил бы одно из следующих выражений:

вызов функции, отличной отconstexpr конструктор для литерального класса,constexpr функция, или неявный вызов тривиального деструктора

S{} а также0 являются константными выражениями, поскольку они не нарушают ни одно из правил в [expr.const].f(x) является постоянным выражением, потому что это вызовconstexpr функция.

Если я что-то упустил, gcc и clang здесь верны.

Решение Вопроса

[Expr.const]:

Выражение е являетсявыражение основной константы если оценка e, следуя правилам абстрактной машины, не оценила бы одно из следующих выражений:

[...]

преобразование lvalue в rvalue, если оно не применяется к

энергонезависимое glvalue целочисленного типа или типа перечисления, которое относится к полному энергонезависимому объекту const с предшествующей инициализацией, инициализированной с помощью константного выражения, илиэнергонезависимое glvalue, которое ссылается на подобъект строкового литерала, илиэнергонезависимое glvalue, которое относится к энергонезависимому объекту, определенному с помощью constexpr, или которое относится к неизменяемому подобъекту такого объекта, илиэнергонезависимое glvalue литерального типа, которое относится к энергонезависимому объекту, время жизни которого началось в пределах оценки e;

[...]

Вf(x), мы делаем преобразование lvalue в rvalue наx. x не является целочисленным или перечислимым типом, это не подобъект строкового литерала, это не объект, определенный с помощью constexpr, и его время жизни не началось с оценкиf(x).

Это, кажется, делает это не основным постоянным выражением.

тем не мение, как указывает Кейси, так какS пусто, ничто в его неявно сгенерированном конструкторе копирования на самом деле не инициировало бы это преобразование lvalue в rvalue Это будет означать, что ничто в этом выражении на самом деле не нарушает каких-либо основных ограничений константного выражения, и, следовательно, gcc и clang правильно его принимают. Эта интерпретация кажется мне правильной.constexpr это весело.

 Casey07 дек. 2017 г., 17:33
f(x), мы делаем преобразование lvalue в rvalue наx«Я думаю, что это ошибочно. Так какS пусто, его конструктор копирования никогда не выполняет преобразование lvalue в rvalue для исходного lvalue. Копия неконстантного выраженияS все еще может быть постоянным выражением (godbolt.org/g/m4jSgz).constexpr иногда бывает безумно
 Barry07 дек. 2017 г., 18:58
@ Кейси, я думаю, это правильная интерпретация. Сумасшедший, действительно.

Ваш ответ на вопрос