I have user-defined type:
class String::CharProxy
{
public:
const char* operator&() const;
char* operator&();
operator char() const;
operator char&();
};
The problem is when I'm trying to perform some explicit casts, the wrong operator is called:
CharProxy p(...);
static_cast<char>(p); // operator char&() call instead of operator char() const
I want operator char() const
to be called when casting to char
and operator char&()
- when casting to char&
only.
Could anyone explain how this mechanism works? Am I mistaken anywhere?
CodePudding user response:
In your static_cast
, both operator char() const
and operator char&()
are candidate functions as per [over.match.conv] because both char
and char&
are convertible to char
via a standard conversion sequence.
Between the two functions, the compiler then decides by standard overload resolution rules. In these, operator char&()
is found to be a better fit because its implicit this
parameter has the same cv-qualifiers as the object you're passing into it (that is: there is no const
qualifier on p
). You can explicitly call the other operator with
static_cast<char>(static_cast<CharProxy const &>(p));
But in more realistic terms: 1. user-defined conversion functions are a hornets' nest that are best avoided 99% of the time, and 2. if your operator char() const
has so different semantics from your operator char&()
that you cannot use the latter where you can use the former, that seems like a very dangerous thing you're building there. Certainly it's not POLA-compliant.
CodePudding user response:
There are two competing overloads. But neither of them is an exact match. The second overload can be called, but it requires doing a standard conversion of the resulting char&
into a char
. The first overload can also be called, but that requires doing a conversion of a reference to p
from CharProxy&
to CharProxy const&
.
Due to various conflict resolution stuff in overload resolution, the former conversion is considered a better fit than the latter.
There's not much you can do about it, nor is there much you should do about it. There should be no functional difference between which one gets called in this circumstance, as the returned reference ought to refer to a char
with the same value that would have been returned by the other one.