Considere este código:
#include <vector>
#include <iostream>
enum class A
{
X, Y
};
struct Test
{
Test(const std::vector<double>&, const std::vector<int>& = {}, A = A::X)
{ std::cout << "vector overload" << std::endl; }
Test(const std::vector<double>&, int, A = A::X)
{ std::cout << "int overload" << std::endl; }
};
int main()
{
std::vector<double> v;
Test t1(v);
Test t2(v, {}, A::X);
}
Isso imprime:
vector overload
int overload
Por que isso não produz um erro de compilação devido à resolução ambígua de sobrecarga? Se o segundo construtor for removido, obteremos vector overload
duas vezes. Como / por qual métrica é int
uma correspondência inequivocamente melhor do {}
que std::vector<int>
?
A assinatura do construtor certamente pode ser melhorada, mas acabei de ser enganado por um trecho de código equivalente e quero garantir que nada de importante seja perdido para esta pergunta.
c++
language-lawyer
overload-resolution
Max Langhof
fonte
fonte
{}
como um bloco de código, atribui 0 a variáveis - exemplo: const char x = {}; é definido como 0 (caractere nulo), o mesmo para int etc.{}
efetivamente faz em certos casos especiais, mas geralmente não é correto (para iniciantes,std::vector<int> x = {};
funciona,std::vector <int> x = 0;
não). Não é tão simples como "{}
atribui zero".struct A { int x = 5; }; A a = {};
não atribui zero em nenhum sentido, ele constrói umA
coma.x = 5
. Isso é diferenteA a = { 0 };
, que inicializaa.x
como 0. O zero não é inerente{}
, é inerente à forma como cada tipo é construído por padrão ou inicializado por valor. Veja aqui , aqui e aqui .Respostas:
Está em [over.ics.list] , ênfase minha
O
std::vector
é inicializado pelo construtor e o marcador em negrito considera uma conversão definida pelo usuário. Enquanto isso, para umint
, essa é a conversão de identidade, por isso supera a classificação do primeiro c'tor.fonte
0
tem tipo,int
mas não tipostd::vector<int>
, como isso é "como se" escrevesse na natureza "não digitada" de{}
?std::vector<int>
. Como você disse, eu esperava que "o tipo do parâmetro acabasse decidindo qual é o tipo do argumento", e um{}
"do tipo" (por assim dizer)std::vector<int>
não deveria precisar de conversão (sem identidade) para inicializar astd::vector<int>
. O padrão obviamente diz que sim, então é isso, mas não faz sentido para mim. (Lembre-se, eu não estou argumentando que você ou o padrão está errado, apenas tentando conciliar isso com meus modelos mentais.)