[conv]/4:
Certain language constructs require that an expression be converted to a Boolean value. An expression
e
appearing in such a context is said to be contextually converted tobool
and is well-formed if and only if the declarationbool t(e);
is well-formed, for some invented temporary variablet
(11.6).
Consider now the snippet below. It doesn't compile, neither in clang, GCC or VS.
struct A{ bool operator!() { return true; } };
int main(){
A a;
bool t(a);
}
Thus, from [conv]/4 we conclude that the type A
is not contextually converted to bool
.
[expr.unary.op]/9:
The operand of the logical negation operator
!
is contextually converted tobool
(Clause 7); its value istrue
if the converted operand isfalse
andfalse
otherwise. The type of the result isbool
.
My understanding of the paragraph above is that the operand of the logical negation operator !
must be contextually converted to bool
. We have just concluded that the type A
is not contextually converted to bool
. Therefore, from [expr.unary.op]/9, we can say that the following code should not compile. But it does, in clang, GCC and VS.
struct A{ bool operator!() { return true; } };
int main(){
A a;
bool t = !a;
}
What am I missing?
[expr] as a whole applies to built-in operators:
Clause [expr] defines the effects of operators when applied to types for which they have not been overloaded.
The definition in [expr.unary.op] is simply the definition of the built-in operator!
. Additionally, [over.match.oper] describes how to look up overloaded operators:
For a unary operator @ with an operand of a type whose cv-unqualified version is T1, [...], three sets of candidate functions, designated member candidates, non-member candidates and built-in candidates, are constructed as follows: [...]
For !a
, you'd have two candidates: your overload A::operator!()
and the built-in defined in [over.built]:
There also exist candidate operator functions of the form
bool operator!(bool);
For the built-in to be selected by overload resolution, the type would have to be contextually converted to bool
† as your argument suggests. However, this candidate is not viable - but the overloaded member operator is.
†T.C. is on top of it as usual, pointing out cwg issue 1919 which indicates that a type that is contextually convertible to bool
still shouldn't use the builtin operator!
due to a wording issue. Although, both gcc and clang permit it (which is what we all want to happen, probably).
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