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 это особый случай, к сожалению, язык - вы можете использовать постоянные целочисленные переменные в качестве константных выражений, поэтому для этих целей мы одинаково относимся к их инициализации.)

Другие вопросы по тегам