Conversion of false to object via const char * con

2019-02-24 23:48发布

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:

  1. 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?
  2. Why does the conversion not work with true? My intuition is that false can be reasonably converted to a nullptr (see also the warning), whereas there is no meaningful pointer value for true.

So, could someone explain what conversion rules apply / do not apply to the two examples above?

3条回答
在下西门庆
2楼-- · 2019-02-25 00:06

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

prog.cc: In function 'A foo()':
prog.cc:17:12: error: could not convert 'false' from 'bool' to 'A'
     return false;
            ^~~~~ 

See live demo here on clang++. It gives following diagnosis.

main.cpp:17:12: error: no viable conversion from returned value of type 'bool' to function return type 'A'
    return false;
           ^~~~~
main.cpp:1:7: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'bool' to 'const A &' for 1st argument
class A
      ^
main.cpp:1:7: note: candidate constructor (the implicit move constructor) not viable: no known conversion from 'bool' to 'A &&' for 1st argument
class A
      ^
main.cpp:10:4: note: candidate constructor not viable: no known conversion from 'bool' to 'const char *' for 1st argument
A::A(const char *s)
   ^
main.cpp:22:12: error: no viable conversion from returned value of type 'bool' to function return type 'A'
    return true;
           ^~~~
main.cpp:1:7: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'bool' to 'const A &' for 1st argument
class A
      ^
main.cpp:1:7: note: candidate constructor (the implicit move constructor) not viable: no known conversion from 'bool' to 'A &&' for 1st argument
class A
      ^
main.cpp:10:4: note: candidate constructor not viable: no known conversion from 'bool' to 'const char *' for 1st argument
A::A(const char *s)
   ^
main.cpp:7:21: warning: private field 'p' is not used [-Wunused-private-field]
        const char *p;
                    ^

false should not convert to pointer type since C++11. See similar question here which I've asked sometimes ago.

查看更多
地球回转人心会变
3楼-- · 2019-02-25 00:16

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, and false evaluates to 0. So false 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 to const char *) followed by a user-defined conversion (const char * to A).

查看更多
看我几分像从前
4楼-- · 2019-02-25 00:16

For 1), false is of type bool, and it can be promoted to an int implicitely:

  • the type bool can be converted to int with the value false becoming ​0​ and true becoming 1.

So, false is basically promoted to NULL/0 (or nullptr), which can be assigned to a pointer.

For 2), §4.10 states that:

A null pointer constant is an integer literal (2.14.2) with value zero or a prvalue of type std::nullptr_t.

A null pointer constant can be converted to a pointer type; [...]

Only a Null pointer constant can be converted to a pointer, and a null pointer constant is either an intergral with value 0 or std::nullptr_t. true (or 1 for that matter) aren't specified, and thus they can't be converted to a pointer.

查看更多
登录 后发表回答