Быстропост.
1. Очевидный, но приконый факт, что в шаблоны можно пихать выражения вроде сигнатуры функций:
std::function<int(int, double)> f;С точки зрения реализации вашего класса это выглядит как-то так:
template <typename T>
struct A {};
template <typename Ret, typename… Args>
struct A<Ret(Args…)> {};Теперь можно в шаблон
A пихать выражения вроде сигнатуры функции. Кроме
std::function такое используется в std::is_function (реализация которой тупо перебор всех возможных видов функций; неудивительно, но дико).2. Вычитал, что выражения
std::is_same_v<char, signed char>;
std::is_same_v<char, unsigned char>;вопреки ожиданиям возвращают
false. Всё потому что char это отдельный тип, который не является (без)знаковым (он какой удобно компилятору на конкретной оси). Ну и signed char не попадает под strict aliasing rule, т.е. unsigned char ближе к char функционально, но формально это разные типы.3. Возможная реализация
std::is_signed/std::is_unsigned выглядит забавно. Тут юзается факт, что беззнаковые числа переполняются:namespace detail {
template <typename T, bool = std::is_arithmetic<T>::value>
struct is_signed : std::integral_constant<bool, T(-1) < T(0)> {};
template <typename T>
struct is_signed<T,false> : std::false_type {};
} // namespace detail
template <typename T>
struct is_signed : detail::is_signed<T>::type {};По факту проверяется верность выражения
T(-1) < T(0), которое для signed типов верно, а для unsigned типов корректно переполняется (потому что переполнение unsigned типов по стандарту не ub) и становится false. У unsigned выражение наоборот:
T(0) < T(-1). Работает аналогично: либо false, либо переполнение и true.