I have built the following minimal example:
class A
{
public:
A(const char *s);
private:
const char *p;
};
A::A(const char *s)
: p(s)
{
}
A foo()
{
return false;
}
A bar()
{
return true;
}
Compiling with g++ (Debian 4.7.2-5) 4.7.2
I get the following:
t.cc: In function 'A foo()':
t.cc:17:10: warning: converting 'false' to pointer type for argument 1 of 'A::A(const char*)' [-Wconversion-null]
t.cc: In function 'A bar()':
t.cc:23:10: error: could not convert 'true' from 'bool' to 'A'
As far as I know, it is possible to use one type T
instead of an instance of class A
, if class A
has a constructor A(T)
. In this case, the value / instance of T is wrapped by the compiler inside a call to the A(T)
constructor.
Also, only one direct implicit conversion is allowed, i.e. no chain A(B(c))
is inserted to convert a value c
of type C
, even if constructors A(B)
and B(C)
exist.
So, my questions:
- Why is
false
converted to a pointer in my example? Sure, a pointer is not an object, but there are still two implicit conversions here. What rule is being applied? - Why does the conversion not work with
true
? My intuition is thatfalse
can be reasonably converted to anullptr
(see also the warning), whereas there is no meaningful pointer value fortrue
.
So, could someone explain what conversion rules apply / do not apply to the two examples above?
The OP 's program fails in compilation in g++ & clang++ when use
-std=c++11
,-std=c++14
.See live demo here on g++ 6.1.0. It gives following error
See live demo here on clang++. It gives following diagnosis.
false should not convert to pointer type since C++11. See similar question here which I've asked sometimes ago.
As published, C++ 11 has the rule "an integral constant expression prvalue of integer type which evaluates to
0
can be converted to any pointer type, yielding the null pointer value of that type." (C++98/03 had a similarly worded rule with the same net effect).bool
is an integer type, andfalse
evaluates to0
. Sofalse
is a valid null pointer constant.Apart from this extra rule, C++ has no implicit conversions from integral types to pointers. Which is why
true
cannot implicitly be converted to a pointer.However, C++14 changed the definition of a null pointer constant so that only integer literals (and not integral constant expressions) qualify.
false
is a boolean literal, not an integer one, so under C++14, the code will not compile.Furthermore, since the issue was recognised by the standard committee as a defect in C++11, newer C++11 compilers are likely to obey the C++14 rules in this regard and not treat
false
as a null pointer constant. Thanks to @Destructor for tracking down the issue status.As to why two implicit conversions seem to be allowed here: the rule is not "at most one implicit conversion is allowed." The rule is "at most one user-defined conversion is allowed." Pointer conversions (such as converting a null pointer constant to a null pointer value) are not classified as user-defined conversions. So the conversion sequence in your case is a pointer conversion (
bool
toconst char *
) followed by a user-defined conversion (const char *
toA
).For 1),
false
is of typebool
, and it can be promoted to anint
implicitely:So,
false
is basically promoted toNULL
/0
(ornullptr
), which can be assigned to a pointer.For 2), §4.10 states that:
Only a
Null pointer constant
can be converted to a pointer, and a null pointer constant is either an intergral with value0
orstd::nullptr_t
.true
(or1
for that matter) aren't specified, and thus they can't be converted to a pointer.