`if constexpr` против`if` в свете оптимизации компилятора и производительности кода

Рассмотрим шаблон функции func это очень важно для производительности. Это может быть реализовано с T=Type1 или какой-то другой тип. Часть функциональной логики зависит от T оно создается с помощью.

Можно либо явно использовать if constexpr (Код B) или используйте ваниль if вместо этого (код A), в то время как компилятор, вероятно, оптимизирует код.

Однако, интересно, как реализация без constexpr (Код А) отличается? Разве компилятор не способен определить, какая ветвь if (в коде A) использовать во время компиляции при создании экземпляра? Может ли он все же (для кода А) генерировать менее эффективный код?

Код А. Без if constexpr:

template<class T>
void func(T argument)
{
    // some general type-independent logic
    if (std::is_same<Type1,T>::value)
    {
        // do something
    }
    else
    {
        // do something else
    }
    // some general type-independent logic
}

Код Б. С if constexpr:

template<class T>
void func(T argument)
{
    // some general type-independent logic
    if constexpr (std::is_same<Type1,T>::value)
    {
        // do something
    }
    else
    {
        // do something else
    }
    // some general type-independent logic
}

Оба кода A и B компилируются, как do something а также do something else хорошо сформированы для любого T,

Есть несколько похожих вопросов:

На вышеупомянутые вопросы нет ответа, если по какой-то причине код В предпочтительнее кода А (в любом случае обе ветви хорошо сформированы).

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

2 ответа

Решение

if constexpr не предназначен для оптимизации. Компиляторы очень хорошо умеют оптимизировать ветку, которая if (true) или же if (false) (поскольку мы говорим о константных выражениях, это то, к чему все сводится). Вот пример Godbolt примера в OP - вы заметите, что и gcc и clang, даже на -O0, не испускайте ветку для простого if,

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

Тем не менее, если у вас есть условие, которое является известным константным выражением - просто всегда используйте if constexprнезависимо от того, нужна ли вам льгота по инстанции. У такого решения нет недостатка. Читателям становится понятнее, что это условие действительно является постоянным (иначе оно даже не скомпилируется). Это также приведет к оценке выражения как константы ( небольшой вариант приводит к тому, что gcc испускает ветку в -O0думал не на -O1), которая с предстоящим добавлением is_constant_evaluated() может стать более важным в долгосрочной перспективе (возможно, даже отрицая мой вступительный абзац).


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

Для решения этой проблемы, в частности, да, std::is_same<X, Y>::value "самоочевидно", что это постоянное выражение... потому что мы случайно знакомы с std::is_same, Но менее очевидно, foo<X>::value является постоянным выражением или foo<X>() + bar<Y>() является постоянным выражением или чем-то более сложным, чем это.

Это видя if constexpr это делает тот факт, что время компиляции говорит само за себя, а не содержание самого условия.

Добавление примера к объяснению @Barry: использование в основном для написания шаблонов. Рассмотрим следующее:

      template <class T>
auto get_value() 
{
    if constexpr (std::is_same_v<T, int>) {
        return 1
    } else {
        return 2.0;
    }
}

Вы можете заметить, что если параметр шаблона равен , возвращаемое значение определяется как , в то время какfloatкогда параметр шаблона неint. Вы увидите, что это не работает с операторами if, не являющимися constexpr, потому что при создании экземпляра все возвращаемые функции должны иметь общий тип, которого нет у первого. Единственный другой способ добиться этого - использовать ограничения С++20 илиstd::enable_ifдля перегрузки функции на основе параметра шаблона.

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