There are two related concepts that you describe as Nil : device type and option type .
Device type
This is because NoneType is in Python and nullptr_t is in C ++, it is just a special type that has a single value that conveys this particular behavior. Since Python is dynamically typed, any object can be compared to None , but in C ++ we can only do this for pointers:
void foo(T* obj) { if (obj == nullptr) {
This is semantically identical to python's:
def foo(obj): if foo is None:
Option Type
Python does not have (or does not need) such a function, but the entire ML family. This can be implemented in C ++ via boost::optional . This is a safe type of encapsulation of the idea that a particular object may or may not matter. This idea is more expressive in a functional family than in C ++:
def foo(obj: Option[T]) = obj match { case None => // "Nil" case case Some(v) => // Actual value case }
Although fairly easy to understand in C ++, as soon as you see this:
void foo(boost::optional<T> const& obj) { if (obj) { T const& value = *obj;
The advantage is that the type of the parameter is the type of the value, and you can easily express the "value" of nothing (for example, your optional<int*> can store nullptr as a value, separate from "Nil"). In addition, it can work with any type, and not just with pointers - you just have to pay for the added functionality. optional<T> will be larger than a T and will be more expensive to use (albeit slightly, although this may not matter much).
A C ++ Nil
We can combine these ideas together to actually make Nil in C ++, at least the one that works with pointers and options.
struct Nil_t { }; constexpr Nil_t Nil; // for pointers template <typename T> bool operator==(const T* t, Nil_t ) { return t == nullptr; } template <typename T> bool operator==(Nil_t, const T* t ) { return t == nullptr; } // for optionals, rhs omitted for brevity template <typename T> bool operator==(const boost::optional<T>& t, Nil_t ) { return !t; }
(Note that we can even generalize this to everything that operator! implements operator!
template <typename T> bool operator==(const T& t, Nil_t ) { return !t; }
but it would be better to confine ourselves to clear cases, and I like the explanations that pointers and advanced options indicate)
Thus:
int* i = 0; std::cout << (i == Nil); // true i = new int(42); std::cout << (i == Nil); // false