struct Foo {};
struct Bar {};
int Baz(const Foo&) { return 0; }
int Baz(Bar&&) { return 1; }
int main()
{
return Baz({});
}
Is this call ambiguous? MSVC chooses the rvalue reference overload. GCC says it is ambiguous. Clang also chooses the rvalue reference but no longer if it's int Baz(std::vector<Bar>&&)
instead or if Bar gets a constructor taking a std::initializer_list.
Is {}
to Bar
a standard conversion sequence?
Can someone explain why this does or does not apply:
- A standard conversion sequence S1 is better than a standard conversion sequence S2 if
[...]
c) or, if not that, both S1 and S2 are binding to a reference parameter to something other than the implicit object parameter of a ref-qualified member function, and S1 binds an rvalue reference to an rvalue while S2 binds an lvalue reference to an rvalue
(https://en.cppreference.com/w/cpp/language/overload_resolution)
As it was already mentioned in the question, the standard says in [over.ics.rank]/(3.2):
Standard conversion sequence
S1
is a better conversion sequence than standard conversion sequenceS2
if...
S1
andS2
are reference bindings (11.6.3) and neither refers to an implicit object parameter of a non-static member function declared without a ref-qualifier, andS1
binds an rvalue reference to an rvalue andS2
binds an lvalue reference...
So GCC is wrong here.
Actually Clang can be similarly deceived by adding default constructors in the structs:
struct Foo {
constexpr Foo() = default;
};
struct Bar {
constexpr Bar() = default;
};
constexpr int Baz(const Foo&) { return 0; }
constexpr int Baz(Bar&&) { return 1; }
int main() {
static_assert( Baz({}) == 1 );
}
MSVC is the compiler that correctly selects Baz(Bar&&)
overload here, demo: https://gcc.godbolt.org/z/sMcx9ro1x
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With