std::common_type
Definido en el archivo de encabezado <type_traits> | ||
template<class... T> struct common_type; | (desde C++11) | |
Determina el tipo común entre todos los tipos T...
, que es el tipo al que todos los tipos T...
pueden ser convertidos implícitamente. Si tal tipo existe (se determina de acuerdo a las reglas posteriores), el tipo miembro type
denomina ese tipo. De lo contrario, no hay un miembro type
.
- Si sizeof...(T) es cero, no hay un miembro
type
. - Si sizeof...(T) es uno (es decir,
T...
contiene solo un tipoT0
), el miembrotype
denomina el mismo tipo que std::common_type<T0, T0>::type si existe; de lo contrario, no hay un miembrotype
. - Si sizeof...(T) es dos (es decir,
T...
contiene exactamente dos tiposT1
yT2
),
- Si aplicar std::decay a al menos uno de
T1
yT2
produce un tipo distinto, el miembrotype
denomina el mismo tipo que std::common_type<std::decay<T1>::type, std::decay<T2>::type>::type, si existe; si no, no hay un miembrotype
. - De lo contrario, si hay una especialización de usuario para std::common_type<T1, T2>, se usa esa especialización;
- De lo contrario, si std::decay<decltype(false?std::declval<T1>():std::declval<T2>())>::type es un tipo válido, el miembro
type
denota ese tipo;
- Si aplicar std::decay a al menos uno de
| (desde C++20) |
- De lo contrario, no hay un miembro
type
.
- De lo contrario, no hay un miembro
- Si sizeof...(T) es mayor que dos (es decir,
T...
consiste en los tiposT1, T2, R...
), entonces si std::common_type<T1, T2>::type existe, el miembrotype
denota std::common_type<std::common_type<T1, T2>::type, R...>::type si tal tipo existe. En todos los demás casos, no hay un miembrotype
.
Los tipos en el paquete de parámetros T
deberá cada uno ser un tipo completo, (posiblemente calificado-cv) void, o un array de límite desconocido. De lo contrario, el comportamiento está indefinido.
Si la instanciación de una plantilla anterior depende, directa o indirectamente, de un tipo incompleto, y esa instanciación podría generar un resultado distinto si ese tipo hipotéticamente se completara, el comportamiento está indefinido.
Contenido |
[editar]Tipos miembro
Nombre | Definición |
type | El tipo común para toda T... |
[editar]Tipos auxiliares
template<class... T> using common_type_t =typename common_type<T...>::type; | (desde C++14) | |
[editar]Especializaciones
Los usuarios pueden especializar common_type
para los tipos T1
y T2
si
- Al menos uno de
T1
yT2
depende de un tipo definido por el usuario, y - std::decay es una transformación de identidad tanto para
T1
como paraT2
.
Si tal especialización tiene un miembro denominado type
, debe ser un tipo miembro público e inequívoco que denomina un tipo que no es una referencia sin calificadores-cv al cual tanto T1
como T2
son explícitamente convertibles. Adicionalmente, std::common_type<T1, T2>::type y std::common_type<T2, T1>::type deben denotar el mismo tipo.
Un programa que agrega especializaciones de common_type
en violación de estas reglas tiene un comportamiento indefinido.
Observa que el comportamiento de un programa que agrega una especialización a cualquier otra plantilla de <type_traits>
está indefinido.
La biblioteca estándar ya proporciona las siguientes especializaciones:
Especializa el rasgo std::common_type. (especialización de plantilla de clase) | |
Especializa el rasgo std::common_type. (especialización de plantilla de clase) |
[editar]Posible implementación
template<typename...>using void_t =void; // plantilla primaria (usada para cero tipos)template<class...>struct common_type {}; //////// un tipotemplate<class T>struct common_type<T>: common_type<T, T>{}; //////// dos tipostemplate<class T1, class T2>using cond_t = decltype(false?std::declval<T1>():std::declval<T2>()); template<class T1, class T2, class=void>struct common_type_2_impl {}; template<class T1, class T2>struct common_type_2_impl<T1, T2, void_t<cond_t<T1, T2>>>{using type =typenamestd::decay<cond_t<T1, T2>>::type;}; template<class T1, class T2>struct common_type<T1, T2>: common_type_2_impl<typenamestd::decay<T1>::type, typenamestd::decay<T2>::type>{}; //////// tres o más tipostemplate<class AlwaysVoid, class T1, class T2, class...R>struct common_type_multi_impl {}; template<class T1, class T2, class...R>struct common_type_multi_impl< void_t<typename common_type<T1, T2>::type>, T1, T2, R...>: common_type<typename common_type<T1, T2>::type, R...>{}; template<class T1, class T2, class... R>struct common_type<T1, T2, R...>: common_type_multi_impl<void, T1, T2, R...>{}; |
[editar]Notas
Para los tipos aritméticos que no están sujetos a promoción, el tipo común puede verse como el tipo de la expresión aritmética (posiblemente de modo mixto) tal que T0()+ T1()+ ... + Tn().
[editar]Ejemplo
Demuestra aritmética de modo mixto en una clase definida por el usuario
#include <iostream>#include <type_traits> template<class T>struct Number { T n;}; template<class T, class U> Number<typename std::common_type<T, U>::type> operator+(const Number<T>& lhs, const Number<U>& rhs){return{lhs.n+ rhs.n};} int main(){ Number<int> i1 ={1}, i2 ={2}; Number<double> d1 ={2.3}, d2 ={3.5};std::cout<<"i1i2: "<<(i1 + i2).n<<"\ni1d2: "<<(i1 + d2).n<<'\n'<<"d1i2: "<<(d1 + i2).n<<"\nd1d2: "<<(d1 + d2).n<<'\n';}
Salida:
i1i2: 3 i1d2: 4.5 d1i2: 4.3 d1d2: 5.8
[editar]Informes de defectos
Los siguientes informes de defectos de cambio de comportamiento se aplicaron de manera retroactiva a los estándares de C++ publicados anteriormente.
ID | Aplicado a | Comportamiento según lo publicado | Comportamiento correcto |
---|---|---|---|
LWG 2141 | C++11 | common_type<int, int>::type es int&& | Tipo del resultado decae |
LWG 2408 | C++11 | common_type no es amigable con SFINAE | Se hizo amigable con SFINAE |
LWG 2460 | C++11 | Es casi imposible escribir las especializaciones para common_type | Se necesita un número reducido de especializaciones |