Consider following code:
#include <memory>
void f( std::shared_ptr<int> ) {}
int main()
{
f( 0 ); // compiles fine in gcc and clang
f( 1 - 1 ); // compiles fine in gcc, fails in clang
constexpr int i = 0;
f( i ); // fails to compile in gcc and clang
f( i - 0 ); // compiles fine in gcc, fails in clang
}
why only f( i )
fails to compile, though i
should be evaluated as compile time constant with value 0?
PS checked with g++ v 5.1.0, it accepts all variants except f(i);
in both c++11 and c++14 mode
PPS checked with clang 3.7, it rejects all variants except literal 0 in both c++11 and c++14 mode
nullptr is a keyword that can be used at all places where NULL is expected. Like NULL, nullptr is implicitly convertible and comparable to any pointer type. Unlike NULL, it is not implicitly convertible or comparable to integral types.
The nullptr keyword represents a null pointer value. Use a null pointer value to indicate that an object handle, interior pointer, or native pointer type does not point to an object. Use nullptr with either managed or native code.
We can use nullptr to explicitly initialize or assign a pointer a null value. In the above example, we use assignment to set the value of ptr2 to nullptr , making ptr2 a null pointer. Use nullptr when you need a null pointer literal for initialization, assignment, or passing a null pointer to a function.
An integral constant expression is an expression that can be evaluated at compile time, and whose type is integral or an enumeration. The situations that require integral constant expressions include array bounds, enumerator values, case labels, bit-field sizes, static member initializers, and value template arguments.
This is a gcc bug. Defect report 903: Value-dependent integral null pointer constants which is a defect report against C++11(it has CD3 status), makes it so that only an integer literal 0
is considered a null pointer constant.
It changed section 4.10
[conv.ptr] paragraph 1
amongst other changes from:
A null pointer constant is an integral constant expression (5.19 [expr.const]) prvalue of integer type that evaluates to zero [...]
to:
A null pointer constant is an integer literal (2.14.2 [lex.icon]) with value zero [...]
This is listed as an incompatibility against C++03, from section C.2.2
Clause 4: standard conversions [diff.cpp03.conv] which says:
Change: Only literals are integer null pointer constants
Rationale: Removing surprising interactions with templates and constant expressions
Effect on original feature: Valid C++ 2003 code may fail to compile or produce different results in this International Standard, as the following example illustrates:void f(void *); // #1 void f(...); // #2 template<int N> void g() { f(0*N); // calls #2; used to call #1 }
The following gcc bug report [C++11] [DR 903] zero-valued integer constant expression should prefer conversion to pointer shows that the gcc team originally thought this was a C++17 change but later changed it to be in effect in C++11.
We can see in the head revision of gcc(6.0) this is fixed (see it live) and produces a diagnostic for all the cases clang does:
error: could not convert '(1 - 1)' from 'int' to 'std::shared_ptr<int>'
f( 1 - 1 ); // compiles fine in gcc, fails in clang
~~^~~
error: could not convert 'i' from 'const int' to 'std::shared_ptr<int>'
f( i ); // fails to compile in gcc and clang
^
error: could not convert '(0 - 0)' from 'int' to 'std::shared_ptr<int>'
f( i - 0 ); // compiles fine in gcc, fails in clang
~~^~~
Because a null pointer constant is defined not just as a compile-time integral constant with value 0, but as an integer literal with value zero (or as a prvalue of type std::nullptr_t
, of course). C++14 (N4140), 4.10/1.
So actually, only the first line f(0)
should compile, all the other ones should provoke at least a diagnostic message from a conforming compiler.
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