【问题标题】:matching nullptr by T *通过 T * 匹配 nullptr
【发布时间】:2016-02-02 12:49:24
【问题描述】:

使用boost::variant的指向AST节点的指针,它可以包含特殊类型的值std::nullptr_t,表示为空,我遇到了问题:[] (auto /* const */ * p) { /* use p */; }形式的通用访问者或以下形式:

struct V
{
    template< typename T >
    void operator () (T /* const */ * p)
    { /* use p */; }
};

无法处理std::nullptr_t 类型的值。

有很多可以想象的解决方法,但问题出现了:有没有很好的解释为什么没有(很可能受到高度限制)decltype(*nullptr) 在语言中输入(*nullptr 格式不正确,std::remove_pointer_t&lt; std::nullptr_t &gt; std::nullptr_tlibc++ 中)?这有理论上的原因吗?

【问题讨论】:

  • "std::nullptr_t 是空指针字面量 nullptr 的类型。它是一种独特的类型,它本身不是指针类型或指向成员类型的指针。"所以std::remove_pointer_t 是多余的。
  • 另外,我认为使nullptr_t 成为一种类型的目的是为了可以为它编写重载和特化,因为很多人使用空值作为标志。
  • abominable function types,但语言中没有此类类型的实例。在这方面,我认为取消引用的 nullptr 的类型与它们相似。
  • @AndyG 在通用代码中我经常只想分离指针并进一步转发它们。
  • std::is_pointerstd::is_null_pointerstd::is_pointer&lt; std::nullptr_t &gt;::value 应该是false。你确定你的静态断言吗?

标签: c++ pointers c++11 metaprogramming generic-programming


【解决方案1】:

是否有很好的解释为什么语言中没有(很可能是高度受限的)decltype(*nullptr) 类型(*nullptr 格式错误,并且 std::remove_pointer_t 在 libc++ 中是 std::nullptr_t )?这有理论上的原因吗?

我认为要回答这个问题,我们必须看看 Herb Sutter 和 Bjarne Stroustrup 提出的N1601

有几个部分对我来说很突出,尤其是

4.10 [conv.ptr]

空指针常量或 nullptr_t 类型的对象可以转换为 指针类型;结果是该类型的空指针值

和 4.11 [conv.mem]:

空指针常量 (4.10) 或 nullptr_t (4.10) 类型的对象可以转换为指针 会员类型;结果是该类型的空成员指针值

因此,如果传递 nullptrnullptr_t 的结果是给定指针类型的空指针,那么取消引用它是有意义的(例如,通过 decltype(*nullptr) 将与取消引用任何其他类型相同空指针。(在 delctype(*nullptr) 的特定情况下,我认为这类似于取消引用空 void*)。也就是说,你不应该这样做。

std::remove_pointer_t<:nullptr_t> 是 std::nullptr_t

这是真的原因很简单,但为什么更难理解。

原因:

std::nullptr_t 是空指针字面量 nullptr 的类型。它是一种独特的类型,它本身不是指针类型或指向成员类型的指针。

鉴于此,std::remove_pointer_t 没有任何效果是有道理的,因为nullptr_t 不是指针类型。

为什么

在 N1601 中,Sutter 和 Stroustrup 说

nullptr_t 不是保留字。它是 中定义的 decltype(nullptr) 的 typedef(如其 _t typedef 所示)。我们不希望在实际程序中看到很多直接使用 nullptr_t 的情况。

事实上,这似乎已经发生了。例如 Clang 3.9.0 在 stddef.h 中有以下内容:

namespace std { typedef decltype(nullptr) nullptr_t; }
using ::std::nullptr_t;

(而且他们对nullptr_t 出现在许多程序中的情况是正确的)。

这仍然不能解释为什么它是这样定义的。要做到这一点,我认为我们需要回到更远的时间到N1488,同样是 Sutter 和 Stroustrup 所说的:

在 C++ 中使用值 0 来表示不同的事物(指针常量和 int)导致 至少自 1985 年以来在 C++ 的教学、学习和使用方面存在的问题。特别是:

  • 区分零和零。空指针和整数0无法区分 非常适合重载解决方案。例如,给定两个重载函数f(int)f(char*), 呼叫f(0) 明确解析为f(int)。没有办法用 空指针值,无需编写显式转换(即f((char*)0))或使用命名变量。 请注意,这意味着今天的空指针0 没有可表达的类型。

  • 命名为空。此外,程序员经常要求空指针常量有一个 名称(而不仅仅是0)。这是宏 NULL 存在的原因之一,尽管该宏是 不足的。 (如果空指针常量有一个类型安全的名称,这也将解决 以前的问题,因为它可以与整数 0 区分开来进行重载解析和 一些错误检测。)

我认为这很好地解释了原因;程序员需要一种方法来区分 in 重载的指针和整数值,并且由于 NULL 通常定义为 0,它通常被解释为整数类型,因此没有简单的方法来强制重载决议选择指针超载。现在我们有了nullptr,我们可以区分指针类型和非指针类型,这完全避免了这个问题。

【讨论】:

    猜你喜欢
    • 2013-01-17
    • 2021-07-01
    • 2021-02-20
    • 2020-01-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多