cinta-ou-igual-Inicializador sindicatos
-
20-12-2019 - |
Pergunta
Relacionados: Como inicializar um não-POD membro da União
O padrão diz
Mais de um não-membro de dados estáticos de uma união pode ter uma cinta-ou-igual-inicializador.
Mas
struct Point {
Point() {}
Point(int x, int y): x_(x), y_(y) {}
int x_, y_;
};
union U {
int z;
double w;
Point p = Point(1,2);
};
#include <iostream>
int main () {
U u;
std::cout << u.p.x_ << ":" << u.p.y_ << std::endl;
}
impressões 4196960:0
em vez do esperado 1:2
.
Eu considero isso um erro de compilador.É isso mesmo?
Solução
C++11 [classe.ctor]/5 estados:
Um padrão construtor para uma classe
X
é um construtor da classeX
que pode ser chamado sem argumentos.Se não houver nenhum usuário declarado construtor para a classeX
, um construtor de não ter parâmetros implicitamente é declarado como inadimplentes (8.4).Uma implicitamente declarado construtor padrão é uminline public
membro de sua classe.Um inadimplentes construtor padrão para a classeX
é definido como excluídos se:
X
é uma união como classe que tem um membro variante com um não-trivial construtor padrão,- qualquer não-membro de dados estáticos, sem cinta-ou-igual-inicializador é do tipo de referência,
- qualquer não-variante não-membro de dados estáticos de const-tipo qualificado (ou matriz dos mesmos), sem cinta-ou-igual-inicializador não tem um usuário padrão fornecido construtor,
X
é uma união, e todos os de sua variante membros são de const-tipo qualificado (ou matriz do mesmo),X
é um não-união da classe e todos os membros de qualquer anónimo-membro da união são de const-tipo qualificado (ou matriz do mesmo),- direta ou classe base virtual, ou não membro de dados estáticos, sem cinta-ou-igual-inicializador, tem tipo de classe
M
(ou matriz dela) eM
não tem nenhum construtor padrão ou de resolução de sobrecarga (13.3) aplicadas aoM
's construtor padrão resulta em uma ambigüidade ou em uma função que é excluído ou inacessível do incumprimento construtor padrão, ou- direta ou classe base virtual ou não membro de dados estáticos tem um tipo com um processo de destruição de que é excluído ou inacessível do incumprimento construtor padrão.
Um construtor padrão é trivial se não for fornecido pelo usuário e se:
- sua classe não tem funções virtuais (10.3) e sem classes base virtuais (10.1), e
- não não membro de dados estáticos de sua classe tem um cinta-ou-igual-inicializador, e
- todos os diretos da base de dados de classes de sua classe padrão trivial de construtores, e
- para todos os não-membros de dados estáticos de sua classe que são do tipo de classe (ou de matriz do mesmo), cada classe tem um construtor padrão trivial.
Caso contrário, o construtor padrão é não-trivial.
Desde a estrutura Point
o OP tem um não-trivial construtor padrão,
Point() {}
um inadimplentes construtor padrão para uma união contendo um membro do tipo Point
deve ser definidos como excluídos de acordo com o primeiro marcador:
X
é uma união como classe que tem um membro variante com um não-trivial construtor padrão
resultando no programa apresentado no OP a ser mal-formado.
No entanto, o comitê parece considerar que este é um defeito no caso em que um membro de uma união cinta-ou-igual-inicializador, por núcleo do grupo de trabalho de problema de 1623:
De acordo com 12.1 [classe.ctor] parágrafo 5,
Um inadimplentes construtor padrão para a classe X é definido como excluídos se:
X
é uma união como classe que tem um membro variante com um não-trivial construtor padrão,...
X
é uma união, e todos os de sua variante membros são de const-tipo qualificado (ou matriz do mesmo),
X
é um não-união da classe e todos os membros de qualquer anónimo-membro da união são de const-tipo qualificado (ou matriz do mesmo),...
Porque a presença de um não-membro de dados estáticos inicializador é o equivalente moral de um mem-inicializador, essas regras devem, provavelmente, ser modificado em definir o construtor gerado como excluído quando um membro da união não-membro de dados estáticos do inicializador.(Nota: a não-referências normativas em 9.5 [classe.união] parágrafos 2-3 e 7.1.6.1 [dcl.escreva.cv] parágrafo 2, que também precisam ser atualizados, se esta restrição é alterado.)
Também seria útil adicionar um requisito para 9,5 [classe.união] exigir que um não-estático de dados inicializador de membro ou de um usuário-desde que o construtor se todos os membros da união têm const qualificado tipos.
Em uma observação mais geral, qual é o construtor padrão definidos como excluídos só porque um membro não-trivial construtor padrão?A própria união não sabe qual membro é o ativo, e o padrão de construção não inicializar os membros de (supondo que não cinta-ou-igual-inicializador).Ele é o "dono" da união para controlar o tempo de vida do membro activo (se houver), e a necessidade de um usuário-desde que o construtor está forçando um padrão de projeto que não faz sentido.No mesmo sentido, qual é o destruidor padrão definidos como excluídos só porque um membro tem um processo de destruição não trivial?Eu concordo com esta restrição se aplicado apenas quando a união também tem um usuário fornecido pelo construtor.
Problema de 1623 tem o status de "elaboração", indicando que o comitê acredita que o problema é provavelmente um defeito - e por que permitir que um cinta-ou-igual-inicializador para um membro da união?- mas ainda não a dedicou o tempo para determinar a adequada formulação de uma resolução.De fato, o parágrafo é praticamente o mesmo no atual C++14 projetos de N3936 ([classe.ctor]/4), exceto que a expressão "direta ou classe base virtual ou não membro de dados estáticos" está em toda parte substituída pelo simples "potencialmente construído subobjecto."
Embora o comportamento de ambos os compiladores não é estritamente em conformidade, eu consideraria Clang para ser comportando-se no espírito da norma.Parece que o GCC torna-se confuso com a combinação de excluídos construtor padrão e cinta-ou-igual-inicializador:
- ele faz diagnosticar o programa como mal-formada, na ausência do cinta-ou-igual-inicializador,
com o cinta-ou-igual-inicializador o presente e o máximo de avisos GCC 4.8.2 não executa nenhuma inicialização da união, e mesmo adverte que os membros são usados não inicializada:
main.cpp: In function 'int main()': main.cpp:17:39: warning: 'u.U::p.Point::y_' is used uninitialized in this function [-Wuninitialized] std::cout << u.p.x_ << ":" << u.p.y_ << std::endl; ^ main.cpp:17:22: warning: 'u.U::p.Point::x_' is used uninitialized in this function [-Wuninitialized] std::cout << u.p.x_ << ":" << u.p.y_ << std::endl; ^
GCC provavelmente deve estar em conformidade com o padrão e diagnosticar o programa como mal formado, ou emular o barulho do comportamento e gerar um bom construtor do cinta-ou-igual-inicializador.