Skip to content

Overload resolution failure with multi-element initializer_list #38928

@itollefsen

Description

@itollefsen
Bugzilla Link 39580
Version 7.0
OS All
CC @DougGregor,@mclow,@zygoloid

Extended Description

Test case:

#include <iostream>
#include <string>
#include <vector>

namespace {

struct Attribute
{
    explicit Attribute(std::string name, std::string value)
        : name(name), value(value) {}
    std::string name;
    std::string value;
};

struct Print
{
    void print(const std::string& s)
    { std::cout << "[String] " << s << std::endl; }

    void print(const std::vector<Attribute>& v)
    { std::cout << "[Vector] " << v[0].name << std::endl; }
};

}

int main()
{
    const Attribute foo("foo", "True");
    const Attribute bar("bar", "True");

    Print p;
    p.print( {foo} );
    p.print( {foo, bar} );

    return 0;
}

Compiling this with Clang 7 (or 6 for that matter), using "-std=c++17 -stdlib=libc++" produces:

error: call to member function 'print' is ambiguous
    p.print( { foo, bar } );

note: candidate function
    void print(const std::string& s)

note: candidate function
    void print(const std::vector<Attribute>& v)

I am not sure whether this is a Clang bug or a libc++ bug. Switching to libstdc++ makes it compile and run just fine. And you get the same error using g++ with libc++ as well, so it's at least in some ways related to the library implementation.

AFAIU, the call with the single-element initializer_list could hit std::string's copy constructor (which might make this related to bug 23812) and therefore discard that overload. That would leave std::vector's initializer_list constructor as the only viable option (I believe), and therefore it works.

But the failing multi-element initializer_list call... It's not telling me which std::string constructor it is considering, so I find it hard to speculate further what's going on there.

There's several ways to work around the problem. Using double braces works, presumably as that reduces it to a single-element initializer_list again. Going via a initializer_list variable also works; auto li = { foo, bar }; t.test(li);

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugzillaIssues migrated from bugzillalibc++libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions