std::is_constant_evaluated поведение
GCC9 уже реализует std::is_constant_evaluated
, Я немного поиграл с этим, и понял, что это несколько сложно. Вот мой тест:
constexpr int Fn1()
{
if constexpr (std::is_constant_evaluated())
return 0;
else
return 1;
}
constexpr int Fn2()
{
if (std::is_constant_evaluated())
return 0;
else
return 1;
}
int main()
{
constexpr int test1 = Fn1(); // Evaluates to 0
int test2 = Fn1(); // Evaluates to 0
int const test3 = Fn1(); // Evaluates to 0
constexpr int test4 = Fn2(); // Evaluates to 0
int test5 = Fn2(); // Evaluates to 1
int const test6 = Fn2(); // Evaluates to 0
}
По этим результатам я извлек следующие выводы:
if constexpr (std::is_constant_evaluated())
всегда оцениваетtrue
ветка. Поэтому нет смысла использовать эту конструкцию.Если компилятор оценивает переменную во время компиляции,
std::is_constant_evaluated())
являетсяtrue
независимо от того, аннотирована ли эта переменнаяconstexpr
или нет.
Я прав?
2 ответа
if constexpr
требует постоянного выражения для условия. Так is_constant_evaluated
конечно всегда будет правдой в таком контексте.
Это предназначено для регулярного if
, Цель состоит в том, чтобы не входить в путь кода, который является недопустимым в constexpr
функция при оценке в постоянном выражении. Но чтобы он выполнялся во время выполнения. Это не для того, чтобы полностью исключить эти пути кода из функции.
Вот как я думаю об этом, может быть, вы найдете это полезным... может быть, нет. Обратите внимание, что я думаю, что писать if constexpr (std::is_constant_evaluated())
будет очень распространенной ошибкой, и попасть в нее легко. Но, надеюсь, компиляторы просто диагностируют этот случай.
По сути, у нас есть два разных правила для кода - типичные правила для нормального кода времени выполнения и ограничения для константных выражений, которые предназначены для constexpr
программирование. Это ограничения expr.const: нет UB, нет reinterpret_cast
и т. д. Эти ограничения продолжают уменьшаться от стандарта к стандарту языка, и это здорово.
По сути, поток управления (с точки зрения пути кода) чередуется между режимом "полного времени выполнения" и constexpr
Режим. Как только мы входим в constexpr
режим (будь то путем инициализации constexpr
объект или вычисление параметра шаблона или...), мы остаемся там до тех пор, пока не закончим... и затем мы возвращаемся в полный режим выполнения.
Какие is_constant_evaluated()
делает просто: я в режиме const expr? Он говорит вам, если вы находитесь в контексте, который требует константных выражений.
С этой точки зрения, давайте посмотрим на if constexpr (is_constant_evaluated())
, Независимо от того, в каком состоянии мы были, if constexpr
требует постоянного выражения в качестве инициализированного, так что это переводит нас в режим const expr, если мы еще не были там. Следовательно, is_constant_evaluated()
это просто правда - безоговорочно.
Однако для if (is_constant_evaluated())
, просто if
не меняет наше состояние между runtime и constexpr. Таким образом, значение здесь зависит от контекста, из которого он был вызван. Инициализация test4
переводит нас в режим const expr, потому что это объект constexpr. Во время его инициализации мы следуем правилам константных выражений... так is_constant_evaluated()
правда. Но как только мы закончим, мы вернемся к правилам времени выполнения... так что в инициализации test5
, is_constant_evaluated()
ложно (А потом test6
это особый случай, к сожалению, язык - вы можете использовать постоянные целочисленные переменные в качестве константных выражений, поэтому для этих целей мы одинаково относимся к их инициализации.)