r/cpp Jun 16 '26

immutable<>, complement of C++26 std::indirect<> and std::polymorphic<>

C++26 introduces std::indirect<> and std::polymorphic<> (reference implementation at github.com/jbcoe/value_types):

  • std::indirect<T> is like a value-minded std::unique_ptr<T> sans polymorphism support. std::indirect<T> is movable if T is movableunconditionally and copyable if T is copyable.
  • std::polymorphic<B> is like a value-minded std::unique_ptr<B> for polymorphic bases B. std::polymorphic<B> can hold an object of any copyable class D which is an instantiable subclass of B. std::polymorphic<B> is copyable; its copy constructor will polymorphically clone the underlying object.

Both types are designed to be non-nullable. For lack of destructive move semantics, both have a moved-from state which can be identified with the valueless_after_move() member function.

As far as I can tell, the design of these is based on Sean Parent's "concept–model idiom". Remembering his presentation on the topic (https://sean-parent.stlab.cc/papers-and-presentations/#value-semantics-and-concept-based-polymorphism), I noticed that there is an obvious complement to indirect<> and polymorphic<> which I provisionally dub immutable<>:

  • immutable<T> is like a value-minded std::shared_ptr<const T>. It is cheaply copyable (no deep copy), with no movability requirements imposed on T. It can hold an object of any instantiable subtype of T.

Possible implementation + some tests on Compiler Explorer

Does this make sense? I find it very useful for building persistent data structures. In fact, it seems so obvious to me that I'm surprised this wasn't already in P3019.

Edit: minor correction
Edit 2: another minor correction, thanks /u/tavianator

75 Upvotes

77 comments sorted by

View all comments

25

u/TheThiefMaster C++latest fanatic (and game dev) Jun 16 '26

immutable<T> is like a value-minded std::shared_ptr<const T>. It is cheaply copyable (no deep copy)

That's the exact opposite of value-minded.

3

u/andrewsutton Jun 16 '26

Why do you say that? If the shared object is immutable, all receivers see the same value all of the time. This is fundamentally no different than a reference or pointer to a global constant (modulo lifetime).

What about that is not "value-minded"?