Conversion from integral constant expression to null-pointer

有些话、适合烂在心里 提交于 2019-12-06 19:26:51

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!