if vs if constexpr внутри функции constexpr - PullRequest
0 голосов
/ 17 декабря 2018

Недавно я изменил некоторые if constexpr на if в моих функциях constexpr и обнаружил, что они все еще работают нормально и могут быть оценены во время компиляции.Вот минимальный случай:

template<int N>
constexpr bool is_negative()
{
    if constexpr  (N >= 0) return false;
    else  return true; 
}
int main()
{
    constexpr  bool v = is_negative<1>();
}

live demo

В случае выше, N должен быть известен во время компиляциипотому что это не тип шаблона параметра, поэтому if constexpr отлично работает здесь.Однако это функция constexpr, поэтому, iirc, можно получить возвращаемое значение, хотя я заменяю if constexpr на if:

template<int N>
constexpr bool is_negative()
{
    if  (N >= 0) return false;
    else  return true; 
}
int main()
{
    constexpr  bool v = is_negative<1>();
}

live demo

С cppref , все требования в A constexpr function must satisfy the following requirements: не включают if.Итак, IIUC, это должно быть поведение, определяемое реализацией, независимо от того, содержит ли функция constexpr if для оценки во время компиляции, даже если все связанные переменные известны во время компиляции (как is_negative выше).

Итак, мойвывод такой:

  • До c ++ 17 у нас нет if constexpr, поэтому выбор равен if, что означает, что не гарантируется, что наши функции constexpr будут оценены при компиляциивремя, все зависит от реализации компилятора
  • После c ++ 17, if constexpr предпочтительнее, если мы хотим, чтобы функции constexpr оценивались во время компиляции.

Все выше - мои личные мысли, может быть, что-то важное пропустил / неправильно понял, не стесняйтесь поправлять меня.Вопрос все еще остается неизменным: if и if constexpr, что должно быть предпочтительнее для функций constexpr, которые должны оцениваться во время компиляции.

ссылки: - Что разрешено в функции constexpr? - Разница между "if constexpr ()" и Vs "if ()"

Ответы [ 2 ]

0 голосов
/ 17 декабря 2018

Разница между if constexpr и if заключается в том, может ли выражение всегда выполняться во время компиляции.В вашем примере вы используете аргумент шаблона, поэтому не имеет значения, какой из них вы пишете.Разницу можно заметить, если у вас будет следующий код:

constexpr bool is_negative(int n)
{
    if  (n >= 0) return false;
    else  return true; 
}
int main(int argc, char**)
{
    constexpr  bool v = is_negative(1);
    bool b = is_negative(argc);
    return static_cast<int>(v || b);
}

Для приведенного выше кода запись if constexpr не будет работать.Поскольку вы можете вызывать функцию со значением времени выполнения.

Опять же, это не должно иметь значения, так как оба пути кода допустимы.При использовании функции с постоянными значениями должны включаться обычные оптимизации компилятора.

Реальный интерес к if constexpr заключается в том, что допустим только один путь:

template <typename T>
constexpr auto get_value(T t) {
    if constexpr(std::is_pointer_v<T>)
        return *t; // deduces return type to int for T = int*
    else
        return t;  // deduces return type to int for T = int
}

Если T будет int, путь кода с *t недопустим, как вы можете 't разыменовываете int.Однако, поскольку каждый использует if constexpr вместо if, код в ложном пути должен быть синтаксически корректным, только если он зависит от аргумента шаблона.

Поскольку вы ищете руководство, компилятор уже требует: Используйте if constexpr, когда один из путей кода недопустим.Используйте if в зависимости от аргументов.

Для случая, когда условие if вычисляется во время компиляции с двумя допустимыми путями, используйте if constexpr, чтобы требовать его оптимизации даже в отладочных сборках, используйте if, если вы хотите пройти через негов отладочных сборках.

Если вы пойдете в крайности, выражение может стать слишком сложным для компилятора, чтобы оптимизировать его в производственной сборке, и в этом случае if constexpr снова может быть интересным, находясь в горячем пути.Лично я еще не был в такой ситуации, однако я не использовал его так много.

0 голосов
/ 17 декабря 2018

До c ++ 17 у нас не было if constexpr, поэтому выбор - if, что означает, что не гарантируется, что наши функции constexpr будут оценены во время компиляции, все зависит от реализации компилятора

Тот факт, что оператор if не является constexpr, не означает, что он не может быть оценен во время компиляции как часть выражения constexpr.В вашем примере v вычисляется во время компиляции в обоих случаях, потому что это необходимо: это константное выражение.Это не определено реализацией.

После c ++ 17, если constexpr предпочтительнее, если мы хотим, чтобы функции constexpr оценивались во время компиляции.

Constexpr, если операторы были введены врешить проблему.Получение функций constexpr для оценки во время компиляции не является такой проблемой.

Вот пример, где требуется constexpr if вместо простого if (взято из cppreference ):

template <typename T>
auto get_value(T t) {
    if constexpr(std::is_pointer_v<T>)
        return *t; // deduces return type to int for T = int*
    else
        return t;  // deduces return type to int for T = int
}

Попробуйте удалить ключевое слово constexpr и посмотрите, что произойдет ( demo ).

Также обратите внимание, что вы всегда можете решить эту проблему, используя другие методы,но if constexpr имеет преимущество краткости.Например, вот эквивалент get_value с использованием диспетчеризации тегов:

template<typename T>
auto get_value_impl(T t, std::true_type) {
    return *t;
}
template<typename T>
auto get_value_impl(T t, std::false_type) {
    return t;
}

template<typename T>
auto get_value(T t) {
    return get_value_impl(t, std::is_pointer<T>{});
}

Demo

...