Consider the following short C++ program:
#include
class B {
public:
operator bool() const {
return false;
}
};
class B2 : pub
The standard states:
A conversion function in a derived class does not hide a conversion function in a base class unless the two functions convert to the same type.
§12.3 [class.conv]
Which means that operator bool
is not hidden by operator int
.
The standard states:
During overload resolution, the implied object argument is indistinguishable from other arguments.
§13.3.3.1 [over.match.funcs]
The "implied object argument" in this case is b
, which is of type B2 &
. operator bool
requires const B2 &
, so the compiler will have to add const to b
to call operator bool
. This -- all other things being equal -- makes operator int
a better match.
The standard states that a static_cast
(which the C-style cast is performing in this instance) can convert to a type T
(in this case int
) if:
the declaration
T t(e);
is well-formed, for some invented temporary variablet
.§5.2.9 [expr.static.cast]
Therefore the int
may be converted to a bool
, and a bool
may equally be converted to a bool
.
The standard states:
The conversion functions of
S
and its base classes are considered. Those non-explicit conversion functions that are not hidden withinS
and yield typeT
or a type that can be converted to typeT
via a standard conversion sequence are candidate functions.§13.3.1.5 [over.match.conv]
So the overload set consists of operator int
and operator bool
. All other things being equal, operator int
is a better match (since you don't have to add constness). Therefore operator int
should be selected.
Note that (perhaps against intuition) the standard does not consider the return type (i.e. the type to which these operators convert) once they have been added to the overload set (as established above), provided the conversion sequence for the arguments of one of them is superior to the conversion sequence for the arguments of the other (which, due to constness, is the case in this instance).
The standard states:
Given these definitions, a viable function F1 is defined to be a better function than another viable function F2 if for all arguments i, ICSi(F1) is not a worse conversion sequence than ICSi(F2), and then
- for some argument j, ICSj(F1) is a better conversion sequence than ICSj(F2), or, if not that,
- the context is an initialization by user-defined conversion and the standard conversion sequence from the return type of F1 to the destination type (i.e., the type of the entity being initialized) is a better conversion sequence than the standard conversion sequence from the return type of F2 to the destination type.
§13.3.3 [over.match.best]
In this case, there is only one argument (the implicit this
parameter). The conversion sequence for B2 &
=> B2 &
(to call operator int
) is superior to B2 &
=> const B2 &
(to call operator bool
), and therefore operator int
is selected from the overload set without regard to the fact that it actually doesn't convert directly to bool
.