Search code examples
c++templatesiteratoroverloadinginitializer-list

Why is this call to the overloaded function ambiguous?


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?


Solution

  • 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.