Compressed std::expected

std::expected is a discriminated union introduced in C++23 that can be seen as a generalization of std::optional in that it stores an error value when std::optional would be empty.

Now, I figure that a lot of types already have unused storage when they are invalid or empty. A simple example would be std::span, which stores a pointer and a size. If the pointer is null, the size has no function and could hold an error value instead.

This would in theory offer the opportunity to optimize the memory consumption of a std::expected<std::span>, because there would be no need to store the discriminator (typically a bool) separately. One could use the pointer as a discriminator instead.

I am sure there are many standard and user types that would provide this opportunity when combined with std::expected.

This could presumably be exploited with partial template specializations for std::expected. If done right, it could be transparent to a user. The memory savings would be automatic, for all types that satisfy the criterium of having an existing member that can serve as the discriminator.

Now my question: Has the standard library been designed with this optimization in mind, and are there implementations that make use of this possibility? What standard types would lend themselves to this kind of optimization? Are existing standard library implementations already exploiting this opportunity?

  • Wouldn’t std::expected be storing an arbitrary error type in the same storage? In that case, there is no value to inspect for special invalid states

    – 

  • If the pointer is null, the size has no function and could hold an error value instead.” What would that error value represent though?

    – 

  • @digito_evo: The error value would be of type E as described in the definition of std::expected, so represents whatever E represents. I’m merely saying that the storage of E can overlap the storage of the size in std::span, for example.

    – 

  • 3

    This is not the first time for the idea. One problem is either violating the encapsulation by exposing class internals of target class through accessor functions, or providing the accessor functions as exposition only with private/freindly access which raises scalability concerns. Another issue would be introducing type-punning in all such classes, which in turn might turn compile time evaluation of such types off. Such a modification in std will take for ever. But you may create and propose your alternative implementation to boost libraries.

    – 




  • 3

    Another point is that std:: expected as well as view types (like std::span) are meant to be used as short lived automatic objects; they’re not supposed to be stored in dynamic containers. So, one important question would be if such optimization is worth the trouble? What would be the impact on execution speed?

    – 

Leave a Comment