Considerar:
struct Person
{
int height;
int weight;
int age;
};
int main()
{
Person p { .age = 18 };
}
O código acima é legal no C99, mas não é legal no C ++ 11.
Como era o c ++ 11 a justificativa do comitê padrão para excluir o suporte para um recurso tão útil?
OVERLAPPED
é um exemplo. Ser capaz de escrever={.Offset=12345};
tornaria o código muito mais claro (e provavelmente menos sujeito a erros). Os soquetes BSD são um exemplo semelhante.main
C99 não é legal. Deve lerstruct Person p = { .age = 18 };
Respostas:
C ++ possui construtores. Se fizer sentido inicializar apenas um membro, isso pode ser expresso no programa, implementando um construtor apropriado. Esse é o tipo de abstração que o C ++ promove.
Por outro lado, o recurso de inicializadores designados é mais sobre expor e tornar os membros fáceis de acessar diretamente no código do cliente. Isso leva a coisas como ter uma pessoa de 18 (anos?), Mas com altura e peso zero.
Em outras palavras, os inicializadores designados oferecem suporte a um estilo de programação em que os internos são expostos e o cliente tem flexibilidade para decidir como deseja usar o tipo.
Em vez disso, C ++ está mais interessado em colocar a flexibilidade do lado do designer de um tipo, para que os designers possam facilitar o uso correto de um tipo e dificultar o uso incorreto. Colocar o designer no controle de como um tipo pode ser inicializado faz parte disso: o designer determina construtores, inicializadores na classe, etc.
fonte
Person
que seu autor deseje fornecer a maior flexibilidade possível para os usuários definirem e inicializarem os membros? O usuário também já pode escreverPerson p = { 0, 0, 18 };
(e por boas razões).Person
tem um design muito C, então os recursos C podem fazer sentido. No entanto, C ++ provavelmente permite um design melhor que também elimina a necessidade de inicializadores designados. - Em minha opinião, remover a restrição de inicializadores de classe para agregados está muito mais de acordo com o ethos de C ++ do que inicializadores designados.Em 15 de julho de 17, P0329R4 foi aceito noc ++ 20padrão: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0329r4.pdf
Isso traz suporte limitado parac99Inicializadores designados de. Esta limitação é descrita a seguir por C.1.7 [diff.decl] .4, dado:
As seguintes inicializações designadas, que são válidas em C, são restritas em C ++:
struct A a = { .y = 1, .x = 2 }
é inválido em C ++ porque os designadores devem aparecer na ordem de declaração dos membros de dadosint arr[3] = { [1] = 5 }
é inválido em C ++ porque a inicialização designada por matriz não é compatívelstruct B b = {.a.x = 0}
é inválido em C ++ porque os designadores não podem ser aninhadosstruct A c = {.x = 1, 2}
é inválido em C ++ porque todos ou nenhum dos membros de dados devem ser inicializados por designadoresPara c ++ 17e Boost anterior, na verdade, tem suporte para inicializadores designados e houve inúmeras propostas para adicionar suporte aoc ++padrão, por exemplo: n4172 e a proposta de Daryle Walker para adicionar designação aos inicializadores . As propostas citam a implementação dec99Inicializadores designados da em Visual C ++, gcc e Clang, afirmando:
Mas o comitê padrão rejeita repetidamente tais propostas , afirmando:
Os comentários de Ben Voigt me ajudaram a ver os problemas intransponíveis dessa abordagem; dado:
Em que ordem essas funções seriam chamadas em c99:
struct X foo = {.a = (char)f(), .b = g(), .c = h()}
? Surpreendentemente, emc99:(Visual C ++, gcc e Clang parecem ter um comportamento acordado, pois todos farão as chamadas nesta ordem :)
h()
f()
g()
Mas a natureza indeterminada do padrão significa que, se essas funções tivessem qualquer interação, o estado do programa resultante também seria indeterminado, e o compilador não o avisaria : Existe uma maneira de ser avisado sobre o mau comportamento de inicializadores designados?c ++ não têm requisitos de lista de inicializador rigorosas 11.6.4 [dcl.init.list] 4:
assim c ++ o suporte teria exigido que fosse executado na ordem:
f()
g()
h()
Quebrando a compatibilidade com o anterior c99implementações.
Conforme discutido acima, este problema foi contornado pelas limitações dos inicializadores designados aceitos emc ++ 20. Eles fornecem um comportamento padronizado, garantindo a ordem de execução dos Inicializadores Designados.
fonte
struct X { int c; char a; float b; }; X x = { .a = f(), .b = g(), .c = h() };
a chamada parah()
é realizada antes def()
oug()
. Se a definição destruct X
não estiver próxima, isso será muito surpreendente. Lembre-se de que as expressões do inicializador não precisam ser livres de efeitos colaterais.Um pouco de hackeagem, então apenas compartilhar por diversão.
E use-o como:
que se expande para:
fonte
$
de tipoT
e você atribui seus membros diretamente antes de retorná-lo. Nifty. Eu me pergunto se há alguma preocupação de desempenho com ele.O inicializador designado está atualmente incluído no corpo de trabalho do C ++ 20: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0329r4.pdf, então podemos finalmente vê-los!
fonte
&
operador retornaria o endereço que o objeto terá durante seu tempo de vida).Dois recursos centrais do C99 que faltam no C ++ 11 mencionam “Inicializadores designados e C ++”.
Acho que o 'inicializador designado' está relacionado com a otimização potencial. Aqui eu uso “gcc / g ++” 5.1 como exemplo.
Sabíamos em tempo de compilação,
a_point.x
é zero, então poderíamos esperar quefoo
fosse otimizado em um únicoprintf
.foo
é otimizado para imprimirx == 0
apenas.Para a versão C ++,
E esta é a saída do código de montagem otimizado.
Podemos ver que
a_point
não é realmente um valor constante de tempo de compilação.fonte
constexpr point(int _x,int _y):x(_x),y(_y){}
. O otimizador do clang ++ parece eliminar a comparação em seu código também. Portanto, este é apenas um problema de QoI.struct addrinfo
oustruct sockaddr_in
, então você fica com atribuições separadas de declarações.