I know I shouldn't do it but still I want to know how it works.
I am trying to compile a buggy code, where the return type of function is std::string
and I am actually returning a boolean value:
// test.cpp
std::string donothing(int i)
{
return false;
}
I know this shouldn't work and the error should be caught be the compiler but there is an interesting observation:
Here are the compiler outputs:
// gcc 4.8.5
test.cpp: In member function ‘virtual std::string donothing(int)’:
test.cpp:9:9: warning: converting ‘false’ to pointer type for argument 1 of ‘std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _CharT*, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]’ [-Wconversion-null]
return false;
// gcc 7.3.1
test.cpp: In member function ‘virtual std::__cxx11::donothing(int)’:
test.cpp:9:9: error: could not convert ‘false’ from ‘bool’ to ‘std::__cxx11::string {aka std::__cxx11::basic_string<char>}’
return false;
^~~~~
By default, GCC 7.3.1 uses -std=gnu++14
. (I cannot find the GCC 7.3.1 manual, but FWIW, both the GCC 7.4 manual and the GCC 6.5 manual say so.)
Let's take a look at the synopsis of the class basic_string
in C++14 ([basic.string]). The only converting (non-explicit) constructor that receive one parameter is: 1
basic_string(const charT* s, const Allocator& a = Allocator());
Therefore, the question is essentially: false
cannot be implicitly converted to const char*
. Per [conv.ptr]/1:
A null pointer constant is an integer literal ([lex.icon]) with value zero or a prvalue of type
std::nullptr_t
. A null pointer constant can be converted to a pointer type; the result is the null pointer value of that type and is distinguishable from every other value of object pointer or function pointer type. Such a conversion is called a null pointer conversion. Two null pointer values of the same type shall compare equal. The conversion of a null pointer constant to a pointer to cv-qualified type is a single conversion, and not the sequence of a pointer conversion followed by a qualification conversion ([conv.qual]). A null pointer constant of integral type can be converted to a prvalue of typestd::nullptr_t
. [ Note: The resulting prvalue is not a null pointer value. — end note ]
false
is a boolean literal ([lex.bool]) rather an integer literal. Therefore, false
cannot be implicitly converted to const char*
.
1 In fact, there is one initializer_list
constructor that meets the criteria, but it is omitted because it is apparently irrelevant.
Per GCC 4.8.5 manual:
The default, if no C++ language dialect options are given, is
-std=gnu++98
.
Again, let's take a look at the synopsis of the class basic_string
in C++98 ([lib.basic.string]). The only converting (non-explicit) constructor that receive one parameter is:
basic_string(const charT* s, const Allocator& a = Allocator());
Therefore, the question is essentially: false
can be implicitly converted to const char*
. Per [conv.ptr]/1:
A null pointer constant is an integral constant expression (expr.const) rvalue of integer type that evaluates to zero. A null pointer constant can be converted to a pointer type; the result is the null pointer value of that type and is distinguishable from every other value of pointer to object or pointer to function type. Two null pointer values of the same type shall compare equal. The conversion of a null pointer constant to a pointer to cv-qualified type is a single conversion, and not the sequence of a pointer conversion followed by a qualification conversion (conv.qual).
false
is an integral constant expression rvalue of integer type (bool
is an integer type) that evaluates to zero. Therefore, false
can be implicitly converted to const char*
.