Объединения условий в enable_if
Иногда мы хотим сильно ограничить свойства типов, с которыми мы хотим инстанцировать шаблон. Например, тип должен быть default-constructed и иметь оператор сравнения. У нас есть для этого метафункция std::enable_if, которая позволяет нам проверять наличие свойств у типов. Но вот незадача, как проверить два условия одновременно? Я хочу и то, и то.
Ранее для этого использовались обычные операторы && и || между тайптрейтами.
Однако в С++17 появились специальные метаклассы, которые позволяют комбинировать условия. Это
• template<class... B> struct conjunction; - логическое И
• template<class... B> struct disjunction; - логическое ИЛИ
• template<class B> struct negation; - логичесткое НЕ
Эти трейты имеют подходящие осмысленные имена, поэтому их использование повышает читаемость кода.
Например, вы можете сочетать эти метафункции с variadic шаблонами
Тогда может появиться что-то такое:
В функцию PrintIntegers мы можем передать сколько угодно(почти) аргументов и все они будут проверяться на соответствие целочисленному типу
Или например вы хотите принтовать только числа? Тогда мы идем к вам:
Если тип - не целочисленный и не с плавающей точкой, то такая перегрузка будет отбрасываться.
Ну и например вы хотите, чтобы функция для вывода в консоль не принимала аргумент-указатель. Тоже можно сделать.
Такие вот удобные метафункции.
Create complex conditions. Stay cool.
#cpp17 #template
Иногда мы хотим сильно ограничить свойства типов, с которыми мы хотим инстанцировать шаблон. Например, тип должен быть default-constructed и иметь оператор сравнения. У нас есть для этого метафункция std::enable_if, которая позволяет нам проверять наличие свойств у типов. Но вот незадача, как проверить два условия одновременно? Я хочу и то, и то.
Ранее для этого использовались обычные операторы && и || между тайптрейтами.
Однако в С++17 появились специальные метаклассы, которые позволяют комбинировать условия. Это
• template<class... B> struct conjunction; - логическое И
• template<class... B> struct disjunction; - логическое ИЛИ
• template<class B> struct negation; - логичесткое НЕ
Эти трейты имеют подходящие осмысленные имена, поэтому их использование повышает читаемость кода.
Например, вы можете сочетать эти метафункции с variadic шаблонами
Тогда может появиться что-то такое:
template<typename... Ts>
std::enable_if_t<std::conjunction_v<std::is_same<int, Ts>...>> PrintIntegers(Ts ... args)
{
(std::cout << ... << args) << 'n';
}
В функцию PrintIntegers мы можем передать сколько угодно(почти) аргументов и все они будут проверяться на соответствие целочисленному типу
Или например вы хотите принтовать только числа? Тогда мы идем к вам:
template<typename T, typename = std::enable_if_t<std::disjunction_v<std::is_integral<T>, std::is_floating_point<T>>>>
void PrintValue(T value)
{
std::cout << "Value: " << value << std::endl;
}
Если тип - не целочисленный и не с плавающей точкой, то такая перегрузка будет отбрасываться.
Ну и например вы хотите, чтобы функция для вывода в консоль не принимала аргумент-указатель. Тоже можно сделать.
template<typename T, typename = std::enable_if_t<std::negation_v<std::is_pointer<T>>>>
void PrintValue(T value)
{
std::cout << "Value: " << value << std::endl;
}
Такие вот удобные метафункции.
Create complex conditions. Stay cool.
#cpp17 #template