【问题标题】:Conversion from integral constant expression to null-pointer从整型常量表达式转换为空指针
【发布时间】:2016-04-03 14:28:02
【问题描述】:

考虑以下代码:

#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 的编译时间常数?

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

【问题讨论】:

  • 编译器知道 0 是“有效”指针 (NULL),否则不是。我不认为这是正确的代码,即使其中一些有效。
  • 我不确定nullptr 是否参与了这个问题;这是关于从intvoid * 的转换。
  • @Tommy 更改为 std::shared_ptr 肯定是 nullptr
  • 请注意,这可以更概括see the live example,我们可以看到clang像gcc一样接受C++03中更一般的例子。

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


【解决方案1】:

这是一个 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]),其值为 0 [...]

这被列为与 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 所做的所有情况生成诊断: p>

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】:

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

所以实际上,只有第一行 f(0) 应该编译,所有其他行至少应该从符合要求的编译器中引发诊断消息。

【讨论】:

  • g++ 即使在 -pedantic 模式下也不提供任何诊断
  • @Slava 从技术上讲,如果还没有一个错误报告,那么它值得。
  • N3242 说“空指针常量是一个整数常量表达式” - 你有 C++14 的链接,上面写着 literal
  • 没关系,N3797 说 literal 就像你引用的那样。从 C++11(和 C)到 C++14 的有趣变化。
  • @Angew 这是一个用于 C++11 的后 C++11 DR,因此它也应该在 C++11 模式下被拒绝。这也是 N4140 将其列为与 C++03 而不是与 C++11 ([diff.cpp03.conv]) 不兼容的原因。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-25
  • 2011-11-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多