Consider this program-
#include <string>
#include <vector>
#include <set>
void fun(const std::string& val) {
}
void fun(std::vector<std::string> val) {
}
int main()
{
std::set<std::string> example;
fun({std::begin(example), std::end(example)});
}
On compilation, I am hitting into these errors-
prog.cc: In function 'int main()':
prog.cc:13:49: error: call of overloaded 'fun(<brace-enclosed initializer list>)' is ambiguous
13 | fun({std::begin(example), std::end(example)});
| ^
prog.cc:4:6: note: candidate: 'void fun(const string&)'
4 | void fun(const std::string& val) {
| ^~~
prog.cc:7:6: note: candidate: 'void fun(std::vector<std::__cxx11::basic_string<char> >)'
7 | void fun(std::vector<std::string> val) {
| ^~~
I understand that std::string
has a constructor overload that takes in an initializer_list
like so-
basic_string( std::initializer_list<char> ilist,
const Allocator& alloc = Allocator() );
and std::vector<std::string>
has an overload that looks like so-
vector( std::initializer_list<std::string> init,
const Allocator& alloc = Allocator() );
So, it is clear that these 2 methods differ in their types. One takes in an initializer_list
of char
and the other of type std::string
.
In my code when I am passing an initializer list of strings cos I pass 2 iterators to a set of strings.
Even then, why does the compiler flag this as an ambiguous call?
The compiler sees an ambiguous call to the following two constructors (note that neither of them take an initializer list):
template <class InputIt>
std::vector::vector (InputIt first, InputIt last, const Allocator& alloc = Allocator());
and
template <class InputIt>
std::string::string (InputIt first, InputIt last, const Allocator& alloc = Allocator());
Now, if you were to actually call the std::string
constructor with those iterator arguments you'd get an error, because they don't dereference to a char. But since that check is not part of the function declaration (e.g. via SFINAE), you're getting the ambiguity error instead.