Грокаем C++
7.53K subscribers
25 photos
3 files
336 links
Два сеньора C++ - Владимир и Денис - отныне ваши гиды в этом дремучем мире плюсов.

По всем вопросам - @ninjatelegramm

Менеджер: @Spiral_Yuri
Реклама: https://telega.in/c/grokaemcpp
Мы на TGstat: https://tgstat.ru/channel/@grokaemcpp/stat
Download Telegram
std::signbit

В прошлом посте мы уже упоминали std::signbit. Сегодня мы посмотрим на эту сущность по-подробнее.

По сути, это самый говорящий и плюсовый чтоли способ узнать знаковый бит числа, который появился в нашем арсенале с приходом С++11. Причем не только целого, но и числа с плавающей точкой. Хотя на самом деле даже наоборот.

bool signbit( float num );  
bool signbit( double num );
bool signbit( long double num );


вот такие перегрузки мы имеем для floating-point чисел. А вот такую:

template< class Integer >  
bool signbit( Integer num );


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

В чем особенность целочисленной перегрузки. В том, что число, которое туда попадает трактуется, как double. Поэтому выражение std::signbit(num) эквивалентно std::signbit(static_cast<double>(num)).

Также эта функция детектирует наличие знакового бита у нулей, бесконечностей и NaN'ов. Да, да. У нуля есть знак. Так что 0.0 и -0.0 - не одно и то же. И если вы внимательные, то заметили даже у NaN есть знак. И std::signbit - один из двух возможных кроссфплатформенных способов узнать знак NaN. Этот факт еще больше мотивирует использовать эту функцию(в ситуациях, где это свойство решает).

Начиная с 23 стандарта функция становится constexpr, что не может не радовать любителей compile-time вычислений.

Для языка С тоже кстати есть похожая сущность. Только там это макрос

#define signbit( arg ) /* implementation defined */


И для него гарантируется такое поведение: для положительных чисел возвращаем ноль, а для отрицательных - ненулевое целое число.

Мне кажется, что в повседневной разработке(там где не нужно выжимать все возможные такты и кода) плюсовое решение будет более предпочтительным, по сравнению с аналогами. Говорящее название и поддержка стандрата - наши главные друзья.

Look for signs in life. Stay cool.

#cpp23 #cpp11 #goodoldc
Обновления в отношениях static_assert и if constexpr

Наш подписчик Вадим упомянул о важном изменении в отношениях static_assert и if constexpr. Эти изменения вступили в силу с приходом С++23 и говорят о том, что теперь программа не считается ill-formed, даже если static_assert фейлится для всех специализаций.

Посмотрим на уже заезженном примере:

template <typename T>
std::string to_str(T t) {
if constexpr (std::is_constructible_v<std::string, T>)
return t;
else if constexpr (std::is_arithmetic_v<T>)
return std::to_string(t);
else
static_assert(false, "cannot convert type to std::string");
}

class A{};

int main()
{
std::cout << to_str("qwe") << std::endl; // OK
std::cout << to_str(5.0) << std::endl; // OK
std::cout << to_str(A{}) << std::endl; // static_assert failed
}


Создали структуру пустышку и использовали функцию to_str по всем трем веткам условия. И если закомментировать последний вывод в консоль - все корректно компилируется и выполняется. Но как только мы инстанцируем специализацию с пессимистичной веткой условия, компиляция падает на ассерте.

Не у многих есть возможность попробовать 23-е плюсы на своих машинках, поэтому оставлю ссылку на годболт, чтобы вы могли поиграться с примером.

До прихода 23-х плюсов была очевидная проблема с этим static_assert'ом. Вроде бы это очень логично писать условия как в примере выше и ожидать, что это сработает. Да и наличие смешного донельзя воркэраунда с шаблонным типозависимым выражением, которое все равно возвращает false, как бы намекает, что что-то не так. Радостно видеть развитие языка и закрытие таких болючих пробелов.

Fix your flaws. Stay cool.

#cpp23 #template