使用 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< std::nullptr_t >
在 libc++ 中是 std::nullptr_t
)?这有理论上的原因吗?
最佳答案
is there good explanation why there no (very likely highly restricted) decltype(*nullptr) type in the language (*nullptr is ill-formed and std::remove_pointer_t< std::nullptr_t > is std::nullptr_t in libc++)? Are there theoretical reasons for this?
我觉得要回答这个问题,必须看N1601由 Herb Sutter 和 Bjarne Stroustrup 提出。
有几个部分对我来说特别突出
4.10 [conv.ptr]
A null pointer constant or an object of type nullptr_t can be converted to a pointer type; the result is the null pointer value of that type
和 4.11 [conv.mem]:
A null pointer constant (4.10) or an object of type nullptr_t (4.10) can be converted to a pointer to member type; the result is the null member pointer value of that type
因此,如果传递 nullptr
或 nullptr_t
的结果是给定指针类型的空指针,那么取消引用它是有意义的(例如,通过 decltype(*nullptr)
将与取消引用任何其他类型的空指针相同。(在 delctype(*nullptr)
的特定情况下,我相信它类似于取消引用 null void*
)。也就是说,你不应该这样做。
std::remove_pointer_t< std::nullptr_t > is std::nullptr_t
这是真的原因很简单,但原因却很难理解。
原因:
std::nullptr_t is the type of the null pointer literal, nullptr. It is a distinct type that is not itself a pointer type or a pointer to member type.
鉴于此,std::remove_pointer_t
没有任何效果是有道理的,因为 nullptr_t
不是指针类型。
原因
在 N1601 中,Sutter 和 Stroustrup 说
nullptr_t is not a reserved word. It is a typedef (as its _t typedef indicates) for decltype(nullptr) defined in <cstddef>. We do not expect to see much direct use of nullptr_t in real programs.
事实上,这似乎是实际发生的事情。例如,Clang 3.9.0 在 stddef.h 中有以下内容:
namespace std { typedef decltype(nullptr) nullptr_t; }
using ::std::nullptr_t;
(而且他们关于在许多程序中出现的 nullptr_t
不多的说法也是正确的)。
这仍然没有解释为什么它是这样定义的。为此,我认为我们需要回到更远一点的时间N1488。 ,也是 Sutter 和 Stroustrup,他们说:
This use of the value
0
to mean different things (a pointer constant and anint
) in C++ has caused problems since at least 1985 in teaching, learning, and using C++. In particular:
Distinguishing between null and zero. The null pointer and an integer
0
cannot be distinguished well for overload resolution. For example, given two overloaded functionsf(int)
andf(char*)
, the callf(0)
unambiguously resolves tof(int)
. There is no way to write a call tof(char*)
with a null pointer value without writing an explicit cast (i.e.,f((char*)0)
) or using a named variable. Note that this implies that today’s null pointer,0
, has no utterable type.Naming null. Further, programmers have often requested that the null pointer constant have a name (rather than just
0
). This is one reason why the macroNULL
exists, although that macro is insufficient. (If the null pointer constant had a type-safe name, this would also solve the previous problem as it could be distinguished from the integer0
for overload resolution and some error detection.)
我认为这很好地解释了原因;程序员需要一种方法来区分 in 重载的指针和整数值,并且由于 NULL
通常定义为 0
,通常被解释为整数类型,因此没有强制重载决议以选择指针重载的简单方法。现在我们有了 nullptr
,我们可以区分指针和非指针类型,从而完全避免了这个问题。
关于c++ - 通过 T * 匹配 nullptr,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35153996/