C++ C+中的“Nil”概念+;

C++ C+中的“Nil”概念+;,c++,null,C++,Null,你记得在大学本科的算法课上,有一个Nil的概念是非常方便的,任何东西都可以分配给它或与之比较。(顺便说一句,我从来没有读过计算机科学的本科。)在Python中,我们可以使用None;在Scala中没有任何东西(如果我理解正确的话,它是所有事物的子对象)。但我的问题是,我们如何在C++中拥有 nIL/COD>?下面是我的想法 我们可以使用定义单例对象,但我目前的印象是,大多数人一想到这一点就会退缩 或者我们可以定义全局或静态 我的问题是,在这两种情况下,我想不出一种方法可以将任何类型的变量赋值给N

你记得在大学本科的算法课上,有一个
Nil
的概念是非常方便的,任何东西都可以分配给它或与之比较。(顺便说一句,我从来没有读过计算机科学的本科。)在Python中,我们可以使用
None
;在Scala中没有任何东西(如果我理解正确的话,它是所有事物的子对象)。但我的问题是,我们如何在C++中拥有<代码> nIL/COD>?下面是我的想法

我们可以使用定义单例对象,但我目前的印象是,大多数人一想到这一点就会退缩

或者我们可以定义全局或静态


我的问题是,在这两种情况下,我想不出一种方法可以将任何类型的变量赋值给
Nil
,或者将任何类型的对象与
Nil
进行比较。Python的
None
很有用,因为Python是动态类型的;Scala的
Nothing
(不要与Scala
Nil
,意思是空列表)优雅地解决了这个问题,因为
Nothing
是所有事物的子对象。那么C++中有一个优雅的方式拥有<代码> nIL/COD> C++吗?逐字表示,C++类型无关,不共享公共值。
通过使用继承可以实现某种形式的可共享值,但必须显式实现,并且只能对用户定义的类型实现。

在C++11中,有一个值nullptr,可以分配给任何指针类型

如果它不是指针类型,它必须在那里。对于特定的值,您可以定义特殊的“我不存在”值,但没有通用的解决方案

如果可能不存在,您的选择是:

  • 指向它并使用nullptr指示不存在的值,或
  • 保留一个单独的标志以指示存在或不存在(这是
    boost::optional
    为您所做的),或者
  • 为此特定用途定义一个特殊值,以表示不存在的值(注意,这并不总是可能的。)

C++遵循的原则是,不使用的东西不需要付费。例如,如果希望一个32位整数存储32位值的完整范围,并附加一个关于它是否为Nil的标志,则这将占用超过32位的存储空间。当然,您可以创建聪明的类来表示这种行为,但它不可用“不在方块”。

< P>在C++中不需要依赖于封装类型的容器(如<代码> Boo::可选< /COD>)。 实际上,有一个组合的原因,因为C++是:< /P>
  • 静态类型化语言:一旦用类型定义变量,它就会坚持该类型(这意味着您不能分配一个值
    None
    ,这不是每个类型可以表示的,您可以用其他动态类型化语言(如Python)来做)
  • 具有内置[1]类型且其类型没有公共基础对象的语言:在所有类型的公共对象中,不能有
    None
    加上“此类型可以表示的所有值”的语义

[1] 与Java内置类型不同,Java内置类型都有相应的类继承自
Java.lang.Object

有两个相关的概念,您称之为
Nil
:和

单位类型 这是什么代码,在python中,<代码> nulppRtxt < /C>是C++,它只是一个特殊类型,它具有一个单一的值,它传达了这个特定的行为。由于Python是动态类型的,任何对象都可以与<代码> >“< < />代码>”进行比较,但是在C++中,我们只能对指针进行这样的操作:

void foo(T* obj) {
    if (obj == nullptr) {
        // Nil
    }
}
这在语义上与python相同:

def foo(obj):
    if foo is None:
        # Nil
选项类型 Python没有(或需要)这样的特性,但所有ML系列都有。这是通过C++实现的。这是一个类型安全的封装的概念,即特定对象可以可能有值,或者没有值。这个概念在函数家族中比在C++中更具表现力:
def foo(obj: Option[T]) = obj match {
    case None => // "Nil" case
    case Some(v) => // Actual value case
}
<>虽然在C++中也很容易理解,但一旦看到它:

void foo(boost::optional<T> const& obj) {
    if (obj) {
        T const& value = *obj;
        // etc.
    }
    else {
        // Nil
    }
}
(注意,我们甚至可以将其推广到任何实现
操作符!

template <typename T>
bool operator==(const T& t, Nil_t ) { return !t; }
模板
布尔运算符==(常数T&T,Nil_T){return!T;}
,但最好将我们自己限制在明确的情况下,我喜欢指针和选项给你的明确性)

因此:

int*i=0;

在大多数这些语言中,变量不是作为对象的名称实现的,而是作为对象的句柄实现的

这样的句柄可以设置为“不保存任何内容”,而额外开销很小。这类似于C++指针,其中<代码> null ptr>代码>状态对应于“指向任何”。

这些语言通常完全依赖于垃圾收集。垃圾收集和强制间接引用数据在实践中都会对性能产生重大影响,并且它们限制了您可以执行的操作类型

在这种语言中使用变量时,必须首先“跟随指针”才能找到真正的对象

C++中,变量名通常指的是实际对象,而不是引用对象。当你在C++中使用变量时,你可以直接访问它。一个额外的状态(对应于“没”)需要在每个变量中额外开销,C++的一个原则是,你不为你使用的东西付费。 <>在C++中有一些方法可以生成“空”数据类型。这些不同于使用原始指针、使用智能指针或使用类似于std::experimantal::optional的东西。它们都有一种“那里什么都没有”的状态,通常通过获取对象并在

bool
上下文中对其进行评估来检测。要访问实际数据(假设存在),请使用一元<代码
template <typename T>
bool operator==(const T& t, Nil_t ) { return !t; }
int* i = 0;
std::cout << (i == Nil); // true
i = new int(42);
std::cout << (i == Nil); // false