July 8th, 2024

What’s the point of std::monostate? You can’t do anything with it!

C++17 introduced std::monostate, 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::monostate, seeing as has no members and only trivial member functions.

The answer is “nothing”.

The purpose of std::monostate 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::variant 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::monostate. 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::variant, you can think of inserting std::monostate as a way to add an “empty” state to a variant,¹ saving you the trouble of having to create a std::optional<std::variant<...>>. You can treat the std::monostate as the “empty” state.

In our usage of std::monostate, 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::variant, known as valueless_by_exception. 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.

Topics
Code

Author

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.

5 comments

Discussion is closed. Login to edit/delete existing comments.

  • Ivan Kljajic

    They should have a 1/0 version of it that creates but excepts if you touch it.

  • LB

    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++.

  • Mark Magagna

    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.

    • Kevin Norris

      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...

      Read more
  • Neil Rashbrook

    I keep hoping reading this blog will make me smarter but it doesn’t seem to be working…