2

I have the following example code. It compiles on clang but it doesn't on Visual Studio 2013.

#include <iostream>
#include <utility>
#include <string>
using namespace std;

void f(const pair<string, string>& p)
{
    cout << p.first << ", " << p.second << endl;
}

void f(initializer_list<pair<string, string> > ps) {
    for (auto p : ps) f(p);
}

int main()
{
    f({ "2", "3" });
    f({ { "2", "3" }, { "3", "4" } });
}

The second call to f fails to compile with:

1error C2668: 'f' : ambiguous call to overloaded function
could be 'void f(std::initializer_list<std::pair<std::string,std::string>>)'
or       'void f(const std::pair<std::string,std::string> &)'
1>          while trying to match the argument list '(initializer-list)'

If I use pairs of int instead of pairs of string it does work fine.

Is anybody aware of a problem like this in Visual Studio? Or am I doing something wrong?

Thank you.

6
  • I'm almost sure I've seen something like this in a bug report.. Commented Oct 2, 2014 at 19:37
  • I suspect the second call is being interpreted as f(pair(string("2", "3"), string("3, 4"))), using the constructor of std::string that takes a pair of iterators (const char* pointers are valid iterators), in addition to "initializer list of pairs" interpretation. Off the top of my head, I can't say whether such an interpretation is legal. Commented Oct 2, 2014 at 19:39
  • @IgorTandetnik is there an initializer list ctor for pair? Commented Oct 2, 2014 at 20:35
  • @Yakk: std::pair is an aggregate; this is why brace-initializer works for it. Commented Oct 3, 2014 at 0:54
  • @IgorTandetnik std::pair is not an aggregate - it's got plenty of user-provided constructors. Commented Oct 3, 2014 at 16:41

1 Answer 1

2

{ { "2", "3" }, { "3", "4" } } may be used to initialize either a initializer_list<pair<string, string> > or a pair<string, string>, in the second case by calling the two-iterator constructor of std::string (and causing UB in the process). Both are list-initialization sequences. Both invoke a user-defined conversion.

§13.3.3.2 [over.ics.rank]/p3:

List-initialization sequence L1 is a better conversion sequence than list-initialization sequence L2 if:

  • L1 converts to std::initializer_list<X> for some X and L2 does not [...]

There's no ambiguity. void f(initializer_list<pair<string, string> > ps); should be unambiguously selected.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.