问题
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
回答1:
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
~~^~~
回答2:
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.
来源:https://stackoverflow.com/questions/34515544/conversion-from-integral-constant-expression-to-null-pointer