Почему количество элементов в списке инициализаторов вызывает неоднозначную ошибку вызова?
Почему первые два вызова doSomething
OK компилятором, но использование двух элементов в списке вызывает неоднозначный вызов?
#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;
}
Ответы
Ответ 1
Что здесь происходит, так это то, что в списке инициализаторов элементов оба строковых литерала могут быть неявно преобразованы в const char*
, так как их тип const char[N]
. Теперь std::vector
имеет конструктор, который принимает два итератора, к которым подходят указатели. Из-за этого конструктор initializer_list
std::vector<std::string>
противоречит конструктору диапазона итератора std::vector<int>
.
Если мы изменим код, вместо него будем
doSomething({"hello"s, "stack"s});
Затем элементы списка инициализаторов теперь std::string
, поэтому нет двусмысленности.
Ответ 2
Оба списка с одним аргументом и тремя аргументами могут соответствовать только конструктору std::vector<std::string>
std::initializer_list
. Однако список с двумя аргументами соответствует одному из конструкторов из std::vector<int>
:
template <class InputIt>
vector(InputIt first, InputIt last, Allocator const &alloc = Allocator());
Действительно, a char const *
можно увеличить и разыменовать, чтобы получить char
, который неявно конвертируется в int
.
Ответ 3
"hello"
и "stack"
оба распадаются на const char *
, что удовлетворяет концепции InputIterator. Это позволяет им сопоставлять конструктор std::vector
конструктор # 4.
Если вы передаете объекты std::string
, неоднозначность будет разрешена.