`if constexpr` против` if` в свете оптимизации компилятора и производительности кода - PullRequest
0 голосов
/ 06 февраля 2019

Рассмотрим шаблон функции 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
}

КодB. С 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.

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

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

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

1 Ответ

0 голосов
/ 06 февраля 2019

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, что делает тот факт, что он сам во время компиляции-объяснительная, а не содержание самого условия.

...