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?

Foi útil?

Solução

C++11 [classe.ctor]/5 estados:

Um padrão construtor para uma classe X é um construtor da classe X que pode ser chamado sem argumentos.Se não houver nenhum usuário declarado construtor para a classe X, um construtor de não ter parâmetros implicitamente é declarado como inadimplentes (8.4).Uma implicitamente declarado construtor padrão é um inline public membro de sua classe.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,
  • 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) e M não tem nenhum construtor padrão ou de resolução de sobrecarga (13.3) aplicadas ao M'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:

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.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top