Pourquoi les deux premiers appels à doSomething
OK par le compilateur, mais l'utilisation de deux éléments dans la liste provoque un appel ambigu?
#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;
}
Ce qui se passe ici, c'est que dans la liste d'initialisation à deux éléments, les deux littéraux de chaîne peuvent être implicitement convertis en const char*
puisque leur type est const char[N]
. Maintenant std::vector
a un constructeur qui prend deux itérateurs auxquels les pointeurs peuvent prétendre. Pour cette raison, le initializer_list
constructeur du std::vector<std::string>
est en conflit avec le constructeur de la gamme d'itérateurs de std::vector<int>
.
Si nous changeons le code à la place
doSomething({"hello"s, "stack"s});
Ensuite, les éléments de la liste d'initialisation sont maintenant std::string
s donc il n'y a pas d'ambiguïté.
Les listes à un argument et à trois arguments ne peuvent correspondre qu'à std::vector<std::string>
's std::initializer_list
constructeur. Cependant, la liste à deux arguments correspond à l'un des constructeurs de std::vector<int>
:
template <class InputIt>
vector(InputIt first, InputIt last, Allocator const &alloc = Allocator());
En effet, un char const *
peut être incrémenté et déréférencé pour obtenir un char
qui est implicitement convertible en int
.
"hello"
et "stack"
se désintègrent tous deux en const char *
ce qui satisfait le concept InputIterator . Cela leur permet de faire correspondre std::vector
le constructeur # 4 .
Si vous passez des objets std::string
, l'ambiguïté est résolue.