Подтвердить что ты не робот

Вызов перегруженного <список с иничиатором, заключенный в скобки) неоднозначен, как с этим бороться?

Я действительно не понимаю этого, я думал, что компилятор сначала выполняет то, что находится в фигурных скобках, а затем дает результат самой подходящей функции. Здесь, похоже, он дает функции список инициализаторов, чтобы справиться с ней...

#include <string>
#include <vector>
using namespace std;

void func(vector<string> v) { }

void func(vector<wstring> v) { }

int main() {
  func({"apple", "banana"});
}

Ошибка:

<stdin>: In function 'int main()':
<stdin>:11:27: error: call of overloaded 'func(<brace-enclosed initializer list>)' is ambiguous
<stdin>:11:27: note: candidates are:
<stdin>:6:6: note: void func(std::vector<std::basic_string<char> >)
<stdin>:8:6: note: void func(std::vector<std::basic_string<wchar_t> >)

Почему не переименована моя func(vector<string> v) перегрузка, и могу ли я сделать ее так?

4b9b3361

Ответ 1

Этот был тонкий.

std::vector имеет конструктор, содержащий два итератора диапазона. Это конструктор шаблон (определенный в 23.6.6.2 стандарта С++ 11):

template<typename InputIterator>
vector(InputIterator first, InputIterator last, 
const allocator_type& a = allocator_type());

Теперь конструктор std::vector<wstring>, принимающий initializer_list, не является совпадением для неявного преобразования в вызове функции, (const char* и string - разные типы); но выше, который, конечно, включен как в std::vector<string>, так и в std::vector<wstring>, является потенциально идеальным совпадением, потому что InputIterator можно вывести как const char*. Если какой-либо метод SFINAE не используется для проверки того, действительно ли аргумент выведенного шаблона действительно удовлетворяет концепции InputIterator для векторного базового типа, что не является нашим случаем, этот конструктор жизнеспособен.

Но опять же, как std::vector<string>, так и std::vector<wstring> имеют жизнеспособный конструктор, который реализует преобразование из скопированного списка инициализаторов: следовательно, двусмысленность.

Таким образом, проблема заключается в том, что хотя "apple" и "banana" на самом деле не являются итераторами (*), они в конечном итоге рассматриваются как таковые. Добавление одного аргумента "joe" к вызову функции устраняет проблему путем устранения неоднозначности вызова, поскольку это вынуждает компилятор исключать конструкторы на основе диапазона и выбирать только жизнеспособное преобразование (initializer_list<wstring> не является жизнеспособный, потому что const char* не может быть преобразован в wstring).


* На самом деле, они являются указателями на const char, поэтому их можно даже рассматривать как постоянные итераторы для символов, но определенно не для строк, как может думать наш конструктор шаблонов.