Reputation: 11317
I'm looking at a wrapping class, based on https://www.fluentcpp.com/category/strong-types/ The main difference is that I'm replacing the get()
method with a explicit casting operator as this triggers questions during code review when used.
As you can see in the simplified code below, I have 3 overloads of the casting operator:
const A &
to int
A &&
to int
const A &
to const int &
When writing: static_cast<int>(a)
, I expect the overload of const A &
to int
to be used. However, it seems to favor the int
and the const int &
overload equally. Why does it do so?
Similarly to this, it seems to allow const int &r = static_cast<const int &>(createA());
which I assume is a life-time bug. (assuming createA returns an A by value)
Simplified code at Compiler Explorer: https://gcc.godbolt.org/z/YMH9Ed
#include <utility>
struct A
{
int v = 42;
explicit operator int() const & { return v; } // Removing this line works
explicit operator int() && { return std::move(v); }
explicit operator const int &() const & { return v; }
};
int main(int, char**)
{
A a;
int r = static_cast<int>(a);
return r;
}
Compilation error:
<source>:14:13: error: ambiguous conversion for static_cast from 'A' to 'int'
int r = static_cast<int>(a);
^~~~~~~~~~~~~~~~~~~
<source>:6:14: note: candidate function
explicit operator int() const & { return v; }
^
<source>:8:14: note: candidate function
explicit operator const int &() const & { return v; }
^
Upvotes: 2
Views: 241
Reputation: 181068
explicit operator int() const & { return v; }
and
explicit operator const int &() const & { return v; }
are equally good conversions. a
is a lvalue so both functions can be called. a
is also not const
so both functions will have to apply a const conversion to a
, so they are both still equally good. All that is left is the "return type", int
or const int&
, but those are both equally good to create anint
from.
You need to get rid of one of conversion operators, or remove the constness from
explicit operator const int &() const & { return v; }
to turn it into
explicit operator const int &() & { return v; }
so non const lvalues give you a const reference.
Upvotes: 3