Здесь у меня есть ряд перегруженных функций, которые имеют в качестве входных данных либо вектор, либо initializer_list. И я хочу обработать особый случай, когда клиентский код вводит пустой initializer_list. Проблема в том, что компилятор не может определить, какие данные должны быть в таком пустом списке. Так что мой вопрос — как я обращаюсь в объявлении функции к такому случаю.
#include <string>
#include <vector>
using namespace std;
void func(vector<string> v) { }
void func(vector<wstring> v) { }
void func(initializer_list<string> iv) {}
void func(initializer_list<wstring> iv) {}
int main() {
using namespace std;
func({"apple", "banana"});
func({L"蘋果", L"香蕉"});
func({}); // special case
}
сообщение об ошибке:
<stdin>: In function 'int main()':
<stdin>:14:10: error: call of overloaded 'func(<brace-enclosed initializer list>)' is ambiguous
<stdin>:14:10: note: candidates are:
<stdin>:5:6: note: void func(std::vector<std::basic_string<char> >)
<stdin>:6:6: note: void func(std::vector<std::basic_string<wchar_t> >)
<stdin>:7:6: note: void func(std::initializer_list<std::basic_string<char> >)
<stdin>:8:6: note: void func(std::initializer_list<std::basic_string<wchar_t> >)
void func(initializer_list<void> iv) {}
— не имеет никакого эффекта. Я не знаю, как правильно это заявить.
Нет способа отличить это с помощью одного параметра. Вы можете сделать один из них шаблоном, который будет более дорогим и менее предпочтительным для разрешения перегрузки.
void func(vector<string> v) { }
void func(vector<wstring> v) { }
template<typename = void>
void func(initializer_list<string> iv) {}
void func(initializer_list<wstring> iv) {}
Сейчас звоню func({})
предпочтет последнюю функцию над шаблоном функции. Обратите внимание, что func({"hello", "world"})
по-прежнему предпочитает шаблон функции перед не-векторной функцией захвата вектора, потому что стоимость преобразования параметра важнее, чем то, был ли кандидат синтезирован из шаблона.
Я надеюсь, что есть лучший ответ, но вы можете использовать тот факт, что инициализация списка с пустыми скобками определенного типа предпочитает конструктор по умолчанию, чем initializer_list
конструктор. К сожалению, это означает необходимость перегрузки перегрузки func
в перегрузочный набор конструкторов одного типа параметра:
using namespace std;
struct parameter {
// representation left as an exercise - perhaps Boost.Variant?
parameter(vector<string> v) {}
parameter(vector<wstring> v) {}
parameter(initializer_list<string> iv) {}
parameter(initializer_list<wstring> iv) {}
parameter() {} // default constructor - func({}) calls this
};
void func(parameter) {}
Если вы не использовали string
Вы можете использовать шаблон, т.е. template<typename T> void func(initializer_list<T>)
с empty
перегрузка, поскольку не шаблонные перегрузки предпочтительнее шаблонных перегрузок, но, к сожалению, в вашем случае строковые литеральные вызовы выводятся как initializer_list<const char *>
, который трудно преобразовать в initializer_list<string>
,