polimorfismo - programação orientada a objetos c++ exercicios resolvidos




Por que a inicialização de agregação não funciona mais desde C++ 20 se um construtor é explicitamente padronizado ou excluído? (2)

Na verdade, o MSDN resolveu sua preocupação no documento abaixo:

Especificação modificada do tipo agregado

No Visual Studio 2019, em / std: c ++ mais recente, uma classe com qualquer construtor declarado pelo usuário (por exemplo, incluindo um construtor declarado = padrão ou = delete) não é um agregado. Anteriormente, somente os construtores fornecidos pelo usuário desqualificariam uma classe de agregação. Essa alteração coloca restrições adicionais sobre como esses tipos podem ser inicializados.

Estou migrando um projeto do C ++ Visual Studio do VS2017 para o VS2019.

Estou recebendo um erro agora, que não ocorreu antes, que pode ser reproduzido com estas poucas linhas de código:

struct Foo
{
    Foo() = default;
    int bar;
};
auto test = Foo { 0 };

O erro é

(6): erro C2440: 'initializing': não é possível converter de 'initializer list' para 'Foo'

(6): note: Nenhum construtor poderia pegar o tipo de fonte, ou a resolução de sobrecarga do construtor era ambígua

O projeto é compilado com o flag /std:c++latest . Eu reproduzi em godbolt . Se eu mudar para /std:c++17 , ele compila bem como antes.

Eu tentei compilar o mesmo código com clang com -std=c++2a e recebi um erro semelhante. Além disso, padronizar ou excluir outros construtores gera esse erro.

Aparentemente, alguns novos recursos do C ++ 20 foram adicionados no VS2019 e estou assumindo que a origem desse problema está descrita em https://en.cppreference.com/w/cpp/language/aggregate_initialization . Lá diz que um agregado pode ser uma estrutura que (entre outros critérios) tem

  • nenhum construtor fornecido pelo usuário, herdado ou explícito (construtores explicitamente padrão ou excluídos são permitidos) (desde C ++ 17) (até C ++ 20)
  • nenhum construtor declarado ou herdado pelo usuário (desde C ++ 20)

Observe que a parte entre parênteses "explicitamente padrão permitido ou construtores excluídos são permitidos" foi descartada e que "fornecido pelo usuário" foi alterado para "declarado pelo usuário".

Então, minha primeira pergunta é: estou certo de que essa mudança no padrão seja a razão pela qual meu código compilou antes, mas não funciona mais?

Claro, é fácil corrigir isso: basta remover os construtores explicitamente padrão.

No entanto, tenho explicitamente padrão e excluído muitos construtores em todos os meus projetos porque achei que era um bom hábito tornar o código muito mais expressivo dessa maneira, pois isso resulta em menos surpresas do que com construtores implicitamente padrão ou excluídos. Com essa mudança, no entanto, isso não parece mais um bom hábito ...

Então, minha pergunta atual é: Qual é o raciocínio por trás dessa mudança de C ++ 17 para C ++ 20? Essa quebra de compatibilidade retroativa foi feita de propósito? Houve algum trade off como "Ok, estamos quebrando compatibilidade retroativa aqui, mas é para o bem maior". O que é esse bem maior?


O resumo da P1008 , a proposta que levou à mudança:

C ++ atualmente permite que alguns tipos com construtores declarados pelo usuário sejam inicializados através de inicialização agregada, ignorando esses construtores. O resultado é um código que é surpreendente, confuso e cheio de bugs. Este artigo propõe uma correção que torna a semântica de inicialização em C ++ mais segura, mais uniforme e mais fácil de ensinar. Também discutimos as alterações que essa correção apresenta.

Um dos exemplos que eles dão é o seguinte.

struct X {
  int i{4};
  X() = default;
};

int main() {
  X x1(3); // ill-formed - no matching c’tor
  X x2{3}; // compiles!
}

Para mim, está bem claro que as mudanças propostas valem a incompatibilidade retroativa que elas carregam. E, de fato, não parece ser mais uma boa prática = default construtores padrão agregados padrão.







c++20