std::conjunction vs &&
Вчера мы поговорили о том, что инстанцирование в std::conjunction и std::disjunction происходит по короткой схеме. Как только мы нашли шаблонный аргумент, для которого будет валидно выражение bool(Bi::value) == false, инстанциация остальных аргументов прекращается и выводится тип std::conjunction::value.
Однако при инстанциации шаблонов операторы && и || не могут похвастаться наличием короткой схемы. Что в форме fold expression, что в явной последовательной форме. То есть
компиляция вот этого кода закончится с ошибкой error: value is not a member of type_without_value<int>. Хотя float - совсем не интергральный тип и при работающей короткой схеме вычислений, ошибки компиляции не было бы. Потому что второй тип даже не инстанцировался бы. Как в случае с std::conjunction.
Такой код успешно скомпилируется и result будет равен false. Потому что инстанциация первого шаблона valid_except_void<T1> завершится успешно и для него bool(value) == false. Поэтому validexceptvoid с войдом не испортит нам игру.
То есть преимущество std::conjunction в том, что как только мы нашли его аргумент, для которого bool(value) == false, то все последующие аргументы не инстанцируются. Это может быть полезно, когда последующие типы очень затратные при инстанцировании или могут вызвать фатальные ошибки, если их инстанцировать с неправильным типом.
Прошу прощение за частое употребление слова "инстанцировать". Я просто не знаю нормального аналога/синонима. Кто знает, поделитесь в комментах.
Для ценителей метапрограммирования оставляю ссылку на годболт, чтобы вы могли поиграться с кодом.
Always compare your tools. Stay cool.
#template #cpp17
Вчера мы поговорили о том, что инстанцирование в std::conjunction и std::disjunction происходит по короткой схеме. Как только мы нашли шаблонный аргумент, для которого будет валидно выражение bool(Bi::value) == false, инстанциация остальных аргументов прекращается и выводится тип std::conjunction::value.
Однако при инстанциации шаблонов операторы && и || не могут похвастаться наличием короткой схемы. Что в форме fold expression, что в явной последовательной форме. То есть
template <class T>
struct type_without_value
{
};
template <class T1, class T2>
constexpr auto numbers = (std::is_integral_v<T1> && type_without_value<T2>::value);
constexpr auto result = numbers<float, int>;
компиляция вот этого кода закончится с ошибкой error: value is not a member of type_without_value<int>. Хотя float - совсем не интергральный тип и при работающей короткой схеме вычислений, ошибки компиляции не было бы. Потому что второй тип даже не инстанцировался бы. Как в случае с std::conjunction.
template <typename T>
struct valid_except_void : std::false_type
{
};
template <>
struct valid_except_void<void>
{
};
template <class T1, class T2>
constexpr auto test = std::conjunction_v<valid_except_void<T1>, valid_except_void<T2>>;
constexpr auto result = test<float, void>;
Такой код успешно скомпилируется и result будет равен false. Потому что инстанциация первого шаблона valid_except_void<T1> завершится успешно и для него bool(value) == false. Поэтому validexceptvoid с войдом не испортит нам игру.
То есть преимущество std::conjunction в том, что как только мы нашли его аргумент, для которого bool(value) == false, то все последующие аргументы не инстанцируются. Это может быть полезно, когда последующие типы очень затратные при инстанцировании или могут вызвать фатальные ошибки, если их инстанцировать с неправильным типом.
Прошу прощение за частое употребление слова "инстанцировать". Я просто не знаю нормального аналога/синонима. Кто знает, поделитесь в комментах.
Для ценителей метапрограммирования оставляю ссылку на годболт, чтобы вы могли поиграться с кодом.
Always compare your tools. Stay cool.
#template #cpp17