C++17 introduced std::
, and I used it as a placeholder to represent the results of a coroutine that produces nothing. In the comments, Neil Rashbrook asked what you are expected to do with a std::
, seeing as has no members and only trivial member functions.
The answer is “nothing”.
The purpose of std::
is to be a dummy type that does nothing. All instances are considered equal to each other. It is basically this:
struct monostate {}; // plus relational operators and a hash specialization
You can see it in libcxx (LLVM/clang), libstdc++ (gcc), and stl (msvc).
But what’s the point of a class that does nothing, and which you can do nothing with?
You don’t use monostate
because you want to do something. You use monostate
when you don’t want to do anything.
Its original purpose was to be used as the initial type in a std::
to allow it to be default-constructed in an empty state.
struct Widget { // no default constructor Widget(std::string const& id); ⟦ other members ⟧ }; struct PortListener { // default constructor has unwanted side effects PortListener(int port = 80); ⟦ other members ⟧ }; std::variant<Widget, PortListener> thingie; // can't do this
The std::variant
‘s default constructor default-constructs its first alternative. Since Widget
doesn’t have a default constructor, you can’t put it first. And PortÂListener
‘s default constructor has unwanted side effects, so we don’t want to put it first.
Enter std::
. You can put that guy first.
std::variant<std::monostate, Widget, PortListener> thingie;
The thingie
default-constructs into a monostate
. What can you do with a monostate
? Nothing! Its job is just to be a dummy type that you can use when you are forced to provide a default-constructible type but don’t want to.
In the case of a std::
, you can think of inserting std::
as a way to add an “empty” state to a variant
,¹ saving you the trouble of having to create a std::
. You can treat the std::
as the “empty” state.
In our usage of std::
, we used it as just a dummy type that stands in for void
.²
¹ More precisely, a way to add another “empty” state to a variant
. There is already an “empty” state for a std::
, known as valueless_
. This state is wacky, though, so you want to avoid it as much as possible. Another topic for another day.
² Bonus reading: Regular Void, which has stalled.
They should have a 1/0 version of it that creates but excepts if you touch it.
Thanks for linking the Regular Void document, I was curious what the latest update on it was. Here’s hoping they can find some way to bring it to reality in C++.
Sounds a lot like the Null Object pattern, where instead of using “null” for something that isn’t there, you construct an object that gives reasonable responses like “I don’t know”. And can do logging etc.
Which is what null was originally supposed to represent.
The null object is just an option type, but without proper type checking. There are times when it's good enough (it is almost always better than a raw null or nil reference, in languages that allow them), and there are times when "I don't know" or "do nothing" is not a suitable behavior (technically: there are times when a null object is not Liskov-substitutable for a non-null object, usually because the non-null object provides one...
I keep hoping reading this blog will make me smarter but it doesn’t seem to be working…