Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

call of overloaded ‘<brace-enclosed initializer list>’ with suffices for pairs is ambiguous

I cannot compile the following code.

void print_number(long n) {
   std::cout << n << std::endl;
}

void print_number(float n) {
   std::cout << n << std::endl;
}

void print_pair(std::pair<std::string, long> p) {
   std::cout << std::get<1>(p) << std::endl;
}

void print_pair(std::pair<std::string, float> p) {
   std::cout << std::get<1>(p) << std::endl;
}

int main() {
   print_number(12l);
   print_number(3.4f);

   print_pair({"long", 12l});
   print_pair({"float", 3.4f});

   return 0;
}

print_number functions work well. However, compiler complains about the overloaded print_pair functions: error: call of overloaded ‘print_pair(<brace-enclosed initializer list>)’ is ambiguous.

Are suffices in <brace-enclosed initializer list> or std::pair not working? How can I overload functions receiving a std::pair parameter?

like image 894
ghchoi Avatar asked Feb 05 '20 12:02

ghchoi


2 Answers

Tl;dr

In order to solve the ambiguity, you can provide the correct type to the compiler:

print_pair(std::make_pair<std::string, long>("long", 12l));
print_pair(std::make_pair<std::string, float>("float", 3.4f));

or

print_pair(std::make_pair(std::string("long"), 12l));
print_pair(std::make_pair(std::string("float"), 3.4f));

The ambiguity problem arises from the fact "long" and "float" are not std::string, but rather const char[].

So when you try to construct a std::pair using the following expression: std::pair{"long", 12l}, what you obtain is a std::pair<const char[5], long>.

(The same for the float; i.e., std::pair<const char[5], float>).

Your overload print_pair accepts std::pair<std::string, long> or std::pair<std::string, float>. None of the previous types match, so the compiler has to perform a conversion. Because of that, it cannot automatically deduct what conversion you want to perform. Both are valid.

For example:

                    std::pair<const char[5], long>  
                                  |
  ----------------------------------------------------------------
  v                                                              v
std::pair<std::string, long>                          std::pair<std::string, float>

To "prove" the problem is the std::string (neither long or float), you can also solve the ambiguity constructing a proper std::string (instead of an array of char):

print_pair(std::make_pair(std::string("long"), 12l));
print_pair(std::make_pair(std::string("float"), 3.4f));

Starting from C++17, this boilerplate can be simplified with:

using namespace std::string_literals;

print_pair(std::pair{"long"s, 12l});
print_pair(std::pair{"float"s, 3.4f});
like image 61
BiagioF Avatar answered Nov 02 '22 23:11

BiagioF


With print_pair({"long", 12l});, there are 2 possible overloads:

  • void print_pair(std::pair<std::string, long>)
  • void print_pair(std::pair<std::string, float>)

{"long", 12l} has no types, but is valid initialization for both std::pair<std::string, long> and std::pair<std::string, long>.

So the call is ambiguous.

print_pair(std::pair{"long", 12l}); would also be ambiguous
as std::pair<const char*, long> can equally be converted to std::pair<std::string, long> and std::pair<std::string, long>.

You have to call it:

  • print_pair(std::pair{std::string("long"), 12l}); to have exact match.
like image 2
Jarod42 Avatar answered Nov 03 '22 01:11

Jarod42