Eu estou brincando com [[no_unique_address]]
no c++20
.
No exemplo em cppreference , temos um tipo Empty
e um tipo vaziosZ
struct Empty {}; // empty class
struct Z {
char c;
[[no_unique_address]] Empty e1, e2;
};
Aparentemente, o tamanho de Z
deve ser pelo menos 2
porque os tipos e1
e e2
são iguais.
No entanto, eu realmente quero ter Z
com tamanho 1
. Isso me fez pensar, que tal empacotar Empty
em alguma classe de empacotador com parâmetro extra de modelo que aplica diferentes tipos de e1
e 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;
};
Infelizmente, sizeof(Z1)==2
. Existe um truque para definir o tamanho de Z1
um?
Estou testando isso com gcc version 9.2.1
eclang version 9.0.0
No meu aplicativo, tenho muitos tipos vazios do formulário
template <typename T, typename S>
struct Empty{
[[no_unique_address]] T t;
[[no_unique_address]] S s;
};
Que é um tipo vazio se T
e S
também são tipos vazios e distintos! Quero que esse tipo fique vazio, mesmo que sejam T
e S
sejam os mesmos.
T
si mesmo? Isso geraria tipos distintos. Neste momento, o fato de que tantoWrapper
é herdamT
está prendendo você ...T
? No momento,T
é um argumento de modelo.T
.Respostas:
Você não pode entender isso. Tecnicamente falando, você não pode sequer garantir que vai ser esvaziar mesmo
T
eS
diferentes tipos vazias. Lembre-se:no_unique_address
é um atributo; a capacidade de ocultar objetos é totalmente dependente da implementação. De uma perspectiva de padrões, você não pode impor o tamanho de objetos vazios.À medida que as implementações do C ++ 20 amadurecem, você deve assumir que
[[no_unique_address]]
geralmente seguirá as regras de otimização da base vazia. Ou seja, desde que dois objetos do mesmo tipo não sejam subobjetos, é provável que você se esconda. Mas, neste momento, é uma espécie de sorte do pote.Quanto ao caso específico de
T
eS
sendo do mesmo tipo, isso simplesmente não é possível. Apesar das implicações do nome "no_unique_address", a realidade é que o C ++ exige que, dados dois ponteiros para objetos do mesmo tipo, esses ponteiros apontem para o mesmo objeto ou tenham endereços diferentes. Eu chamo isso de "regra de identidade exclusiva" eno_unique_address
não afeta isso. De [intro.object] / 9 :Membros de tipos vazios declarados
[[no_unique_address]]
com tamanho zero, mas ter o mesmo tipo torna isso impossível.De fato, pensar nisso, tentar ocultar o tipo vazio via aninhamento ainda viola a regra de identidade exclusiva. Considere o seu
Wrapper
eZ1
caso. Dado umz1
exemplo de que é uma instânciaZ1
, fica claro quez1.e1
ez1.e2
são objetos diferentes com tipos diferentes. No entanto,z1.e1
não está aninhadoz1.e2
nem vice-versa. E enquanto eles têm tipos diferentes,(Empty&)z1.e1
e não(Empty&)z1.e2
são tipos diferentes. Mas eles apontam para objetos diferentes.E pela regra de identidade exclusiva, eles devem ter endereços diferentes. Assim, mesmo que
e1
ee2
são nominalmente diferentes tipos, seus internos também devem identidade única obedecer contra outros subobjects no mesmo objeto que contém. Recursivamente.O que você deseja é simplesmente impossível no C ++ como está atualmente, independentemente de como você tenta.
fonte
Até onde eu sei, isso não é possível se você quiser ter os dois membros. Mas você pode se especializar e ter apenas um dos membros quando o tipo for igual e vazio:
Obviamente, o restante do programa que usa os membros precisaria ser alterado para lidar com o caso em que há apenas um membro. Não importa qual membro é usado nesse caso - afinal, é um objeto sem estado sem endereço exclusivo. As funções de membro mostradas devem tornar isso simples.
Você pode introduzir mais especializações para oferecer suporte à compactação recursiva de pares vazios:
Ainda mais, para comprimir algo parecido
Empty<Empty<A, char>, A>
.fonte
sizeof(Empty<Empty<A,A>,A>{})==2
ondeA
é uma estrutura completamente vazio.get_empty<T>
função. Em seguida, você pode reutilizar aget_empty<T>
esquerda ou a direita, se ela já estiver funcionando lá.