通过T *匹配nullptr

时间:2016-02-02 12:49:24

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

使用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格式不正确 libc ++ 中的std::remove_pointer_t< std::nullptr_t >std::nullptr_t?这有理论上的原因吗?

1 个答案:

答案 0 :(得分:4)

  

有没有很好的解释为什么语言中没有(很可能是高度限制的)decltype(* nullptr)类型(* nullptr是格式错误的,而std :: remove_pointer_t&lt; std :: nullptr_t&gt;是std :: nullptr_t in的libc ++)?这有理论上的原因吗?

我想回答这个问题,我们必须看看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)的特定情况下,我认为它类似于取消引用null void*)。也就是说,你不应该这样做。

  

的std :: remove_pointer_t&LT; std :: nullptr_t&gt;是std :: nullptr_t

这是真的很简单,但为什么更难以获得。

原因:

  

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

鉴于此,std::remove_pointer_t无效,因为nullptr_t不是指针类型。

为什么

在N1601中,Sutter和Stroustrup说

  

nullptr_t不是保留字。它是&lt; cstddef&gt;中定义的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并不多。

这仍然没有解释 WHY 它是如此定义的。要做到这一点,我想我们需要回到N1488更远的地方,同时他们也会说:Sutter和Stroustrup:

  

使用值0表示C ++中的不同内容(指针常量和int)导致   自1985年以来在教学,学习和使用C ++方面遇到的问题。特别是:

     
      
  • 区分null和zero。无法区分空指针和整数0   很好的超载分辨率。例如,给定两个重载函数f(int)f(char*),   来电f(0)明确地解析为f(int)。没有办法用{a}来拨打f(char*)   空指针值,无需编写显式强制转换(即f((char*)0))或使用命名变量。   请注意,这意味着今天的空指针0没有可编辑的类型。

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

  •   

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