Considera 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);
}
Esto imprime:
vector overload
int overload
¿Por qué esto no produce un error de compilación debido a una resolución de sobrecarga ambigua? Si se elimina el segundo constructor, obtenemos vector overloaddos veces. ¿Cómo / por qué métrica es intuna combinación inequívocamente mejor {}que std::vector<int>?
La firma del constructor seguramente se puede recortar aún más, pero acabo de engañarme con un código equivalente y quiero asegurarme de que no se pierda nada importante para esta pregunta.
c++
language-lawyer
overload-resolution
Max Langhof
fuente
fuente

{}como un bloque de código, asigna 0 a las variables - ejemplo: const char x = {}; se establece en 0 (null char), lo mismo para int etc.{}efectivamente hace en ciertos casos especiales, pero generalmente no es correcto (para empezar,std::vector<int> x = {};funciona,std::vector <int> x = 0;no lo hace). No es tan simple como "{}asigna cero".struct A { int x = 5; }; A a = {};no asigna cero en ningún sentido, construye unAcona.x = 5. Esto es diferenteA a = { 0 };, que se inicializaa.xa 0. El cero no es inherente a{}, es inherente a cómo cada tipo se construye por defecto o se inicializa en valor. Mira aquí , aquí y aquí .Respuestas:
Está en [over.ics.list] , énfasis mío
El
std::vectorconstructor lo inicializa y la viñeta en negrita lo considera una conversión definida por el usuario. Mientras tanto, para unaint, esta es la conversión de identidad, por lo que supera el rango del primer c'tor.fuente
0tiene el tipointpero no el tipostd::vector<int>, ¿cómo es eso un "como si" fuera de la naturaleza "sin tipo"{}?std::vector<int>. Como dijiste, esperaba que "el tipo de parámetro termine decidiendo cuál es el tipo de argumento", y un{}"tipo" (por así decirlo)std::vector<int>no debería necesitar una conversión (no de identidad) para inicializar astd::vector<int>. El estándar obviamente dice que sí, así que eso es todo, pero no tiene sentido para mí. (Eso sí, no estoy argumentando que usted o el estándar están equivocados, solo estoy tratando de conciliar esto con mis modelos mentales.)