Полезные новации С++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 может быть использована для замены уже существующих трюков:
https://tech.io/playgrounds/2205/7-features-of-c17-that-will-simplify-your-code/constexpr-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
https://medium.com/@LoopPerfect/c-17-vs-c-14-if-constexpr-b518982bb1e2
http://filipjaniszewski.com/2016/07/29/c17-lets-have-a-look-at-the-constexpr-if/
https://blog.tartanllama.xyz/if-constexpr/
http://filipjaniszewski.com/2016/07/29/c17-lets-have-a-look-at-the-constexpr-if/
https://blog.tartanllama.xyz/if-constexpr/
Комментарии
Отправить комментарий