c++ - ¿Por qué el número de elementos en una lista de inicializador causa un error de llamada ambiguo?
initializer-list ambiguous (3)
Las listas de uno y tres argumentos solo pueden coincidir con el constructor
std::vector<std::string>
std::initializer_list
std::vector<std::string>
.
Sin embargo, la lista de dos argumentos coincide con uno de los constructores de
std::vector<int>
:
template <class InputIt>
vector(InputIt first, InputIt last, Allocator const &alloc = Allocator());
De hecho, un
char const *
puede incrementarse y desreferenciarse para obtener un
char
que sea convertible implícitamente en un
int
.
¿Por qué son las dos primeras llamadas a hacer algo correcto por el compilador, pero el uso de dos elementos en la lista provoca una llamada ambigua?
#include <vector>
#include <string>
void doSomething(const std::vector<std::string>& data) {}
void doSomething(const std::vector<int>& data) {}
int main(int argc, char *argv[])
{
doSomething({"hello"}); // OK
doSomething({"hello", "stack", "overflow"}); // OK
doSomething({"hello", "stack"}); // C2668 ''doSomething'': ambiguous call
return 0;
}
Lo que sucede aquí es que en la lista de inicializadores de dos elementos, ambos literales de cadena se pueden convertir implícitamente en
const char*
ya que su tipo es
const char[N]
.
Ahora
std::vector
tiene un constructor que toma dos iteradores para los que califican los punteros.
Debido a eso, el constructor
initializer_list
de
std::vector<std::string>
está en conflicto con el constructor de rango de iterador de
std::vector<int>
.
Si cambiamos el código para que sea
doSomething({"hello"s, "stack"s});
Entonces, los elementos de la lista de inicializadores ahora son
std::string
s, por lo que no hay ambigüedad.
"hello"
y
"stack"
descomponen para
const char *
que satisface el concepto
InputIterator
.
Esto les permite hacer coincidir
el constructor # 4 de
std::vector
.
Si pasa objetos
std::string
, la ambigüedad se resuelve.