std::conjunction - cppreference.com
De cppreference.com
|
|
(desde C++17) | |
Forma la conjunción lógica de los rasgos de tipo B..., efectivamente llevando a cabo un AND lógico en la secuencia de rasgos.
La especialización std::conjunction<B1, ..., BN> tiene una base pública e inequívoca que es
- si
sizeof...(B) == 0,std::true_type; de lo contrario, - el primer tipo
BienB1, ..., BNpara el quebool(Bi::value) == false, oBNsi no existe tal tipo.
Los nombres de los miembros de la clase base, excepto conjunction y operator=, no están ocultos y están inequivocadamente disponibles en conjunction.
La conjunción es de cortocircuito: si hay un argumento de plantilla de tipo Bi con bool(Bi::value) == false, entonces instanciar conjunction<B1, ..., BN>::value no requiere la instanciación de Bj::value para j > i.
El comportamiento de un programa que añade especializaciones para conjunction o conjunction_v no está definido.
Parámetros de plantilla
| B... | - | Todo argumento de plantilla Bi para el que Bi::value se instancia debe ser utilizable como una clase base y definir el miembro value, que es convertible a bool.
|
Plantilla de variable auxiliar
|
|
(desde C++17) | |
Posible implementación
template<class...> struct conjunction : std::true_type { }; template<class B1> struct conjunction<B1> : B1 { }; template<class B1, class... Bn> struct conjunction<B1, Bn...> : std::conditional_t<bool(B1::value), conjunction<Bn...>, B1> {};
Notas
Una especialización de conjunction no necesariamente hereda de std::true_type o de std::false_type: simplemente hereda de la primera B cuyo miembro ::value, explícitamente convertido a bool, es false, o de la última B cuando todos pueden convertirse a true. Por ejemplo, std::conjunction<std::integral_constant<int, 2>, std::integral_constant<int, 4>>::value es 4.
La instanciación de cortocircuito diferencia a conjunction de las expresiones de pliegue: una expresión de pliegue como (... && Bs::value) instancia toda B en Bs, mientras que std::conjunction_v<Bs...> detiene la instanciación una vez que el valor puede determinarse. Esto es particularmente útil si el tipo posterior es costoso de instanciar o puede causar un error grave cuando se instancia con el tipo incorrecto.
Ejemplo
#include <iostream> #include <type_traits> // func se habilita si todas las Ts... tienen el mismo tipo que T template<typename T, typename... Ts> std::enable_if_t<std::conjunction_v<std::is_same<T, Ts>...>> func(T, Ts...) { std::cout << "todos los tipos en el paquete son T\n"; } // de lo contrario template<typename T, typename... Ts> std::enable_if_t<!std::conjunction_v<std::is_same<T, Ts>...>> func(T, Ts...) { std::cout << "no todos los tipos en el paquete son T\n"; } int main() { func(1, 2, 3); func(1, 2, "hola!"); }
Salida:
todos los tipos en el paquete son T no todos los tipos en el paquete son T