Полезные новации С++17. constexpr if.

if времени компиляции для С++!

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

if constexpr(cond) statement1; // Discarded if cond is false else statement2; // Discarded if cond is true

Например:

template <typename T> auto get_value(T t) { if constexpr (std::is_pointer_v<T>) return *t; else return t; }

#include <iostream>
#include <memory>

template <typename T>
auto get_value(T t) {
    if constexpr (std::is_pointer_v<T>)
        return *t;
    else
        return t;
}

int main()
{
     auto pi = std::make_unique<int>(9);
     int i = 9;
     
     std::cout << get_value(pi.get()) << "\n";
     std::cout << get_value(i) << "\n";
}

constexpr if может быть использована для замены уже существующих трюков:

  • техника SFINAE по удалению не подходящих функций при перегрузке,
  • std::enable_if, появившаяся в С++14, может быть легко заменена на constexpr if,
  • диспетчеризация тегов.
Простой пример - последовательность Фибоначчи:

template<int N> constexpr int fibonacci() {return fibonacci<N-1>() + fibonacci<N-2>(); } template<> constexpr int fibonacci<1>() { return 1; } template<> constexpr int fibonacci<0>() { return 0; }

Теперь нет необходимости в специализациях и код становится более понятным:

template<int N> constexpr int fibonacci() { if constexpr (N>=2) return fibonacci<N-1>() + fibonacci<N-2>(); else return N; }

Необходимо учитывать, что "логика короткого замыкания" не работает для  if constexpr и будет во время компиляции вычисляться всё выражение, например попытка инстанцировать do_thing(3) в следующем примере будет вызывать ошибку компиляции


#include <iostream>
#include <type_traits>

struct MyType
{
static const int i = 5;
};

template<typename T>
void do_thing(const T &t)
{
if constexpr (std::is_same_v<MyType, T> && T::i == 5) {
std::cout << "MyType::i == 5\n";
}
else {
std::cout << "don't know...\n";
}
}

int main()
{
do_thing(MyType());
do_thing(3); // fails to compile because of the T::i expression in the if-constexpr above
}


Ещё пример взятия элемента структуры по индексу:


#include <iostream>
#include <string>

struct S 
{
    int n;
    std::string s;
    float d;
};

template <std::size_t I>
auto& get(S& s)
{
    if constexpr (I == 0)
        return s.n;
    else if constexpr (I == 1)
        return s.s;
    else if constexpr (I == 2)
        return s.d;
}

int main()
{
S obj { 0, "hello", 10.0f };
    std::cout << get<0>(obj) << ", " << get<1>(obj) << "\n";
}


Подробности:

https://tech.io/playgrounds/2205/7-features-of-c17-that-will-simplify-your-code/constexpr-if






Комментарии

Популярные сообщения из этого блога

Полезные новации С++17. Выражения свертки (Fold expressions)

Перегрузка и специализация шаблонных функций.

Ещё о перегрузке шаблонных функций (Partial ordering)