使用指向AST节点的指针的boost::variant (可以包含特殊类型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< std::nullptr_t >是std::nullptr_t in libc++),这有很好的解释吗?这是否有理论上的原因?
发布于 2016-02-02 13:29:32
有很好的解释吗?为什么在语言中没有(非常可能是高度限制的)解密类型(*nullptr是错误的,std::remove_pointer_t< std::nullptr_t > std::nullptr_t在libc++中)?这是否有理论上的原因?
我认为要回答这个问题,我们必须看看N1601由Herb和Bjarne提出。
有几个部分对我来说很突出,特别是
4.10 conv.ptr
可以将空指针常量或nullptr_t类型的对象转换为指针类型;结果是该类型的空指针值。
和4.11 conv.mem
可以将空指针常量(4.10)或nullptr_t类型的对象(4.10)转换为成员类型的指针;结果是该类型的空成员指针值。
因此,如果传递nullptr或nullptr_t的结果是给定指针类型的空指针,那么取消引用它(例如,通过decltype(*nullptr) )将与取消引用任何其他类型的空指针相同。(在delctype(*nullptr)的具体例子中,我认为它类似于取消引用空void*)。也就是说,你不应该这么做。
std::remove_pointer_t< std::nullptr_t > is std::nullptr_t
这是正确的理由是很容易的,但原因是很难理解。
原因是:
T是空指针文本nullptr的类型。它本身不是指针类型,也不是成员类型的指针,这是一个独特的类型。
考虑到这一点,std::remove_pointer_t不会产生任何影响,因为nullptr_t不是指针类型。
为什么
在N1601中,Sutter和Stroustrup说
nullptr_t不是一个保留字。中定义的解密类型(Nullptr)的类型类型(Nullptr)。我们不希望看到在实际程序中直接使用nullptr_t。
事实上,这似乎就是实际发生的情况。例如,clang3.9.0在stddef.h中有如下内容:
namespace std { typedef decltype(nullptr) nullptr_t; }
using ::std::nullptr_t;(而且他们说得对,在许多程序中出现的nullptr_t并不多)。
这仍然不能解释为什么它被定义为这样。要做到这一点,我认为我们需要回到更远一点的N1488,也就是Sutter和Stroustrup,他们说:
使用
0值来表示C++中的不同事物(指针常量和int)至少自1985年以来在教学、学习和使用C++方面造成了问题。特别是:
0不能很好地区分。例如,给定两个重载函数f(int)和f(char*),调用f(0)将明确地解析为f(int)。如果不写入显式强制转换(即f(char*) )或使用命名变量,就无法用空指针值编写对f((char*)0)的调用。请注意,这意味着今天的空指针0没有可说话的类型。0)。这是宏NULL存在的原因之一,尽管该宏是不够的。(如果空指针常量具有类型安全名称,则还可以解决前面的问题,因为可以将其与整数0区分开来,以进行过载解析和一些错误检测。)我认为这很好地解释了为什么;程序员需要一种方法来区分重载中的指针和整数值,而且由于NULL通常被定义为0 (通常被解释为整数类型),因此没有一种简单的方法可以强制重载解析来选择指针重载。现在我们有了nullptr,我们可以区分指针类型和非指针类型,从而完全避免了这个问题。
https://stackoverflow.com/questions/35153996
复制相似问题