Я действительно не понимаю этого, я думал, что компилятор сначала выполняет то, что в скобках, а затем дает результат наиболее подходящей функции. Здесь похоже, что она дает функции список инициализатора, чтобы справиться с ней …
#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)
вызвана перегрузка, и можно ли так сделать?
Этот был тонким.
std::vector
имеет конструктор, принимающий два итератора диапазона. Это шаблон конструктор (определенный в 23.6.6.2 Стандарта C ++ 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
так что они могут даже рассматриваться как постоянные итераторы для персонажи, но определенно не для строк, как думает наш конструктор шаблонов.
Других решений пока нет …