从积分常量表达式转换为空指针

时间:2015-12-29 17:02:16

标签: c++ c++11 gcc null c++14

请考虑以下代码:

#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
}

为什么只有f( i )无法编译,尽管i应该被评估为值为0的编译时常量?

使用g ++ v 5.1.0检查PS,它在c ++ 11和c ++ 14模式下接受除f(i);以外的所有变体 使用clang 3.7检查PPS,它拒绝除c ++ 11和c ++ 14模式中的文字0之外的所有变体

2 个答案:

答案 0 :(得分:20)

这是一个gcc错误。 Defect report 903: Value-dependent integral null pointer constants 这是针对C ++ 11的缺陷报告(它具有CD3状态),使得只有整数文字0被视为空指针常量。

更改了4.10 [conv.ptr]段1部分以及其他更改:

  

空指针常量是整数类型的整数常量表达式(5.19 [expr.const])prvalue,其计算结果为零[...]

为:

  

空指针常量是一个整数文字(2.14.2 [lex.icon]),其值为零[...]

这被列为与C ++ 03的不兼容,来自C.2.2条款第4条:标准转换 [diff.cpp03.conv] ,其中包含:

  

更改:只有文字是整数空指针常量
  理由:删除模板和模板的令人惊讶的交互   常数表达   对原始功能的影响:有效的C ++ 2003代码可能无法编译或   在本国际标准中产生不同的结果   以下示例说明:

void f(void *); // #1
void f(...); // #2
template<int N> void g() {
  f(0*N); // calls #2; used to call #1
}

以下gcc错误报告[C++11] [DR 903] zero-valued integer constant expression should prefer conversion to pointer显示gcc团队最初认为这是C ++ 17更改,但后来将其更改为在C ++ 11中生效。

我们可以在gcc( 6.0 )的头版修订版中看到这是固定的( see it live ),并为clang所做的所有案例生成诊断:

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
    ~~^~~

答案 1 :(得分:6)

因为空指针常量不仅定义为值为0的编译时整数常量,而且定义为值为零的整数 literal (或作为prvalue)当然是std::nullptr_t类型的。 C ++ 14(N4140),4.10 / 1。

实际上,只有第一行f(0)应该编译,所有其他行应该至少引起来自符合编译器的诊断消息。