TGViewer
Грокаем C++ Грокаем C++ @grokaemcpp · 9.35K subscribers
Post #209 2.26K
​if constexpr. Мотивация.

Представим, что мы хотим определить, равны ли два числа, потенциально разных типов. Казалось бы, что задачка очень простая. Но это только на первый взгляд.

На самом деле это тривиально только для интегральных типов. a == b на этом все. Но вот для чисел с плавающей точкой все не так тривиально. Чисто исходя из того, что из себя представляют такие числа и как с ними оперировать, нельзя их сравнивать оператором ==. Корректное сравнение представляет собой сравнение модуля разности двух чисел с некоторой очень маленькой величиной epsilon. Если расстояние между двумя числами находится в пределах допускаемой нами погрешности, тогда эти числа равны.

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

Только вот это не очень эффективно с точки зрения производительности. Для целых чисел мы могли бы использовать один оператор, а тут будем использовать 3 действия - вычитание, взятие модуля и сравнение. Поэтому хотелось бы эти ветки разделить, чтобы они не пересекались. А сделать это можно с помощью шаблонов и sfinae. Для С++14 код будет выглядеть примерно так:

templete <class T>
constexpr T absolute(T arg) {
return arg < 0 ? -arg : arg;
}

template <class T>
constexpr std::enable_if_t<std::is_floating_point<T>::value, bool>
is_equal(T a, T b) {
return absolute(a - b) < static_cast<T>(0.000001);
}

template <class T>
constexpr std::enable_if_t<!std::is_floating_point<T>::value, bool>
is_equal(T a, T b) {
return a == b;
}


Как видите, здесь используется std::enable_if. Код проверяет тип аргументов функции и направляет нужные типы в нужную перегрузку. Но как будто бы это очень сложно. И много кода просто повторяется. Хочется две эти перегрузки как-то объединить. Тем более тут вообще явно проглядываются две ветки условия, при ложном и правдивом исходе. Разве просто if тут не подойдет? Тут может и подойдет. Но не всегда обычный if в принципе может являться опцией. Давайте рассмотрим такой пример.

Мы хотим универсальную функцию to_str, которая возвращает строку, сделанную из переданного параметра. Используя стандартный if мы пишем:

template <class T>
std::string to_str(T t) {
if (std::is_same_v<T, std::string>)
return t;
else
return std::to_string(t);
}

auto str = to_str("10"s);


И при попытке это дело скомпилировать мы получим неожиданную ошибку: компилятор отказывается находить перегрузку функции std::to_string для std::basic_string. И правильно делает, ведь такой перегрузки нет. Но как же так? is_same дает true и мы можем просто вернуть строку без преобразований. Но не так все просто.

Компилятору нужно проверить весь код функции на корректность. Чтобы все символы резолвились, синтаксис соблюдался и вызывались корректные перегрузки. Во всех ветках кода. И в этом примере при попадании строки в функцию для нее не найдется перегрузка для std::to_string,

И вот очень хочется, чтобы в ложных ветках компилятор расслабился, немного почилил и разрешил нам в них некоторые вольности.

И с этим очень хорошо справляется if constexpr. То есть статический if. Условие времени компиляции. Как хотите. В следующем посте подробнее разберем эту конструкцию и с чем ее едят.

Choose the right path and don't overanalyze others. Stay cool.

#cpp14 #template #compiler
  • 🔥 14
  • 👍 9
  • ❤ 6
  • 🥰 1
More from @grokaemcpp
  1. Oct 14, 2026​​Что внутри std::condition_variable? #опытным Более менее все знакомы с примитивом синхро…
  2. Oct 12, 2026​​WAT #новичкам Как вы думаете, результат выражения: bool math = -1 < 1U; будет правдой ил…
  3. Oct 8, 2026​​Strict weak ordering #опытным На первый взгляд, всё выглядит рабочим: мы создаём 40 зака…
  4. Oct 7, 2026​​Где-то баг... #опытным Вот вам код: struct Order { int price; int id; }; int main() { st…
  5. Oct 5, 2026Откуда spurious wakeup на кондваре? #опытным У кондваров есть метод std::condition_variabl…
  6. Oct 1, 2026​​Stacktrace. Tips #опытным Чтобы полноценно работать со стандартными трейсами, нужно знат…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →