Estoy jugando con [[no_unique_address]]adentro c++20.
En el ejemplo de cppreference tenemos un tipo Emptyy un tipo vacíosZ
struct Empty {}; // empty class
struct Z {
char c;
[[no_unique_address]] Empty e1, e2;
};
Aparentemente, el tamaño de Ztiene que ser al menos 2porque los tipos de e1y e2son iguales.
Sin embargo, realmente quiero tener Zcon el tamaño 1. Esto me hizo pensar, ¿qué pasa con el ajuste Emptyen alguna clase de contenedor con un parámetro de plantilla adicional que impone diferentes tipos de e1y e2?
template <typename T, int i>
struct Wrapper : public T{};
struct Z1 {
char c;
[[no_unique_address]] Wrapper<Empty,1> e1;
[[no_unique_address]] Wrapper<Empty,2> e2;
};
Por desgracia, sizeof(Z1)==2. ¿Hay algún truco para hacer el tamaño de Z1ser uno?
Estoy probando esto con gcc version 9.2.1yclang version 9.0.0
En mi solicitud, tengo muchos tipos vacíos del formulario
template <typename T, typename S>
struct Empty{
[[no_unique_address]] T t;
[[no_unique_address]] S s;
};
¡Cuál es un tipo vacío si Ty Stambién son tipos vacíos y distintos! Quiero que este tipo esté vacío, incluso si Ty Sson los mismos tipos.

Tsí mismo? Eso generaría distintos tipos. En este momento, el hecho de que ambosWrapperhereden teTestá frenando ...T? En este momento,Tes un argumento de plantilla.T.Respuestas:
No puedes entender eso. Técnicamente hablando, ni siquiera se puede garantizar que va a estar vacío, incluso si
TySson diferentes tipos vacías. Recuerda:no_unique_addresses un atributo; la capacidad de ocultar objetos depende completamente de la implementación. Desde una perspectiva estándar, no puede imponer el tamaño de los objetos vacíos.A medida que las implementaciones de C ++ 20 maduren, debe suponer que
[[no_unique_address]]generalmente seguirá las reglas de optimización de base vacía. Es decir, siempre que dos objetos del mismo tipo no sean subobjetos, es probable que espere esconderse. Pero en este punto, es una especie de suerte.En cuanto al caso específico
TySser del mismo tipo, eso simplemente no es posible. A pesar de las implicaciones del nombre "no_unique_address", la realidad es que C ++ requiere que, dados dos punteros a objetos del mismo tipo, esos punteros apunten al mismo objeto o tengan direcciones diferentes. Yo llamo a esto la "regla de identidad única", yno_unique_addressno afecta eso. Desde [intro.object] / 9 :Miembros de tipos vacíos declarados como
[[no_unique_address]]de tamaño cero, pero tener el mismo tipo lo hace imposible.De hecho, al pensar en ello, intentar ocultar el tipo vacío a través de la anidación todavía viola la regla de identidad única. Considere su caso
WrapperyZ1. Dadoz1que es una instancia deZ1, está claro quez1.e1yz1.e2son diferentes objetos con diferentes tipos. Sin embargo,z1.e1no está anidado dentroz1.e2ni viceversa. Y si bien tienen diferentes tipos,(Empty&)z1.e1y no(Empty&)z1.e2son diferentes tipos. Pero sí señalan diferentes objetos.Y por la regla de identidad única, deben tener diferentes direcciones. Así que aunque
e1ye2son nominalmente diferentes tipos, sus componentes internos también deben obedecer identidad única contra otros objetos parciales en el mismo objeto que contiene. Recursivamente.Lo que quiere es simplemente imposible en C ++ tal como está actualmente, independientemente de cómo lo intente.
fuente
Por lo que puedo decir, eso no es posible si quieres tener ambos miembros. Pero puede especializarse y tener solo uno de los miembros cuando el tipo es el mismo y está vacío:
Por supuesto, el resto del programa que usa los miembros necesitaría ser cambiado para tratar el caso donde solo hay un miembro. No debería importar qué miembro se usa en este caso; después de todo, es un objeto sin estado sin una dirección única. Las funciones miembro mostradas deberían simplificar eso.
Podría introducir más especializaciones para admitir la compresión recursiva de pares vacíos:
Aún más, comprimir algo así
Empty<Empty<A, char>, A>.fuente
sizeof(Empty<Empty<A,A>,A>{})==2cuandoAes una estructura completamente vacío.get_empty<T>función. Luego, puede volver a usarlo a laget_empty<T>izquierda o derecha si ya funciona allí.