Есть ли причина использовать std :: conunction/std :: disjunction вместо выражения сгиба над "&&"/"||"?
Существуют ли какие-либо конкретные случаи, которые вы не можете правильно сделать с помощью std::conjunction
/std::disjunction
и не использовать более "фундаментальное" (то есть, языковое, а не библиотечное) складное выражение над &&
/||
?
Пример:
// func is enabled if all Ts... have the same type
template<typename T, typename... Ts>
std::enable_if_t<std::conjunction_v<std::is_same<T, Ts>...> >
func(T, Ts...) {
// TODO something to show
}
против
// func is enabled if all Ts... have the same type
template<typename T, typename... Ts>
std::enable_if_t<(std::is_same<T, Ts> &&...)>
func(T, Ts...) {
// TODO something to show
}
Версия, использующая выражение сгиба, является более краткой и, как правило, более читаемой (хотя мнения могут отличаться по этому вопросу). Поэтому я не понимаю, почему он был добавлен в библиотеку вместе с выражениями свертки.
Ответы
Ответ 1
std::conjunction
короткого замыкания ::value
std::conjunction
conunction, в то время как выражение сгиба нет. Это означает, что, учитывая:
template <typename T>
struct valid_except_void : std::false_type { };
template <>
struct valid_except_void<void> { };
Будет скомпилировано следующее:
template <typename... Ts>
constexpr auto test = std::conjunction_v<valid_except_void<Ts>...>;
constexpr auto inst = test<int, void>;
Но следующее не будет:
template <typename... Ts>
constexpr auto test = (valid_except_void<Ts>::value && ...);
constexpr auto inst = test<int, void>;
живой пример на godbolt.org
Из контекста:
Соединение имеет короткое замыкание: если есть аргумент типа шаблона Bi
с bool(Bi::value) == false
, то создание экземпляра conjunction<B1,..., BN>::value
не требует создания экземпляра Bj::value
для j > i
.