Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Rvalue reference overload confusion

49 views
Skip to first unread message

Paavo Helde

unread,
Jan 26, 2022, 8:55:46 AM1/26/22
to

Today I was surprised by an unexpected conversion from NSVC++ 2019. The
code example is here:

#include <iostream>

class A {
public:
A(size_t) {}
};

enum e { e1, e2, e3 };

class B {
public:
B(e) {}
};

void foo(A&&) {
std::cout << "Overload A\n";
}

void foo(const B&) {
std::cout << "Overload B\n";
}

int main() {
foo(e1);
}

MSVC++ 2019 compiles this fine and chooses overload A. g++ refuses to
compile it and reports an ambiguity. Who is right?

PS. If one replaces foo(A&&) with foo(const A&), then also MSVC reports
an ambiguity.

Öö Tiib

unread,
Jan 26, 2022, 9:44:00 AM1/26/22
to
I suspect gcc is correct but cant bring normative proofs. The MSVC has its
legacy of being overly permissive there. I'm not even sure if it has stopped
accepting rvalues to initialise non-const lvalue references yet. Anyway I
like whatever diagnostics of doubt about whatever implicit conversions
as these keep causing major illusions and confusions.

Bonita Montero

unread,
Jan 26, 2022, 9:50:23 AM1/26/22
to
Maybe it would help to use a scoped enum which hasn't an implicit
conversion to int.

Paavo Helde

unread,
Jan 26, 2022, 11:26:29 AM1/26/22
to
26.01.2022 16:50 Bonita Montero kirjutas:
> Am 26.01.2022 um 15:43 schrieb Öö Tiib:
>> On Wednesday, 26 January 2022 at 15:55:46 UTC+2, Paavo Helde wrote:
>>> Today I was surprised by an unexpected conversion
>
> Maybe it would help to use a scoped enum which hasn't an implicit
> conversion to int.

Yes, in new code scoped enums should be certainly preferred. Changing
them the scoped enums in old codebases is harder.

Bonita Montero

unread,
Jan 26, 2022, 11:32:44 AM1/26/22
to
When I have enums which are part of a namespace I mostly don't use
them, when I have enums which are part of a class I never use them.

Andrey Tarasevich

unread,
Jan 26, 2022, 11:46:29 AM1/26/22
to
The example can be simplified by taking `enum` out of the picture

#include <iostream>

class A {
public:
A(int) {}
};

class B {
public:
B(int) {}
};

void foo(A&&) {
std::cout << "Overload A\n";
}

void foo(const B&) {
std::cout << "Overload B\n";
}

int main() {
foo(0);
}

it will still exhibit the same behavior, but now it is fully
"symmetrical" with regard to `A` and `B`.

Experimenting with the example shows that MSVC seems to over-prioritize
the existing rule that binding rvalue reference to an rvalue is better
than binding an lvalue reference
http://eel.is/c++draft/over.ics.rank#3.2.3

However, in this case the two conversion sequences are incomparable
because they involve _different_ user-defined conversions. (In order to
be comparable they should use the same user-defined conversion.) This is
what is supposed to be recognized as an ambiguity by the compiler
http://eel.is/c++draft/over.ics.rank#3.3

If we simplify the example to a mere

#include <iostream>

class A {
public:
A(int) {}
};

void foo(A&&) {
std::cout << "Overload rvalue\n";
}

void foo(const A&) {
std::cout << "Overload lvalue\n";
}

int main() {
foo(0);
}

both candidate paths will use the the same user-defined conversion. The
call is no longer ambiguous, since the above
"rvalue-is-better-than-lvalue" logic kicks in.

--
Best regards,
Andrey Tarasevich

wij

unread,
Jan 27, 2022, 5:50:54 AM1/27/22
to
Another quick thought without testing: The ctor B(e) might consider using 'explicit'

class B {
public:
explicit B(e) {};
};

Juha Nieminen

unread,
Jan 28, 2022, 2:35:59 AM1/28/22
to
wij <wyn...@gmail.com> wrote:
> Another quick thought without testing: The ctor B(e) might consider using 'explicit'
>
> class B {
> public:
> explicit B(e) {};
> };

'explicit' is a severely underused keyword. (So much so that some C++
experts think that it should be the default, and that it would be better
if you had to explicitly use an 'implicit' keyword to make the constructor
implicit, rather than the other way round. But alas, backwards
compatiblity...)

Öö Tiib

unread,
Jan 28, 2022, 6:27:12 AM1/28/22
to
Similar situation is with overused keyword "const", it would benefit language
to have it default and some kind of "var" or "mut" for mutable stuff.
Alas, backwards compatibility.

Alf P. Steinbach

unread,
Jan 28, 2022, 7:30:39 AM1/28/22
to
#define VAR auto
#define LET const auto

- Alf

0 new messages