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
S1is a better conversion sequence than standard conversion sequenceS2if...
S1andS2are reference bindings (11.6.3) and neither refers to an implicit object parameter of a non-static member function declared without a ref-qualifier, andS1binds an rvalue reference to an rvalue andS2binds 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