So you're checking on every access? That sounds like it's hiding a potentially expensive operation. If we were to have a feature like that, it feels like it would be worth generalising it to expression variables and, ultimately, call by name. 

On Sun, Jun 25, 2023, 12:53 Frederick Virchanza Gotham via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
Let's say you started out writing a program with a global object:

    T g_obj;

Now let's say that over 15 years, your program gets a lot bigger and
so now you want to start conserving RAM. This global object has a
constructor that allocates 100 megabytes of RAM, and so you decide to
delay its construction until it's actually needed, so you change it
to:

    optional<T> g_obj;

Of course this would mean that you need to edit the code everywhere so
that you have "g_obj->" instead of "g_obj.", unless of course you were
to do:

    optional<T> g_optional_obj;
    T &g_obj = *g_optional_obj.operator->();

Strictly speaking this is undefined behaviour but it will work fine so
long as you make sure to 'emplace' the object before using 'g_obj'.

But what if we could standardise a way of doing this that doesn't
result in undefined behaviour? One possibility could be code that
works something like as follows:

    #include <cassert>               // cassert
    #include <optional>              // optional, bad_optional_access

    using std::optional;
    using T = int;

    optional<T> g_optional_obj;

    #define NDEBUG   // Try commenting this out

    #ifdef NDEBUG
    #   define g_obj (   g_optional_obj.has_value()            \
                       ? g_optional_obj.value()                \
                       : throw std::bad_optional_access() )
    #else
    #   define g_obj ( assert(g_optional_obj.has_value()),     \
                       g_optional_obj.value() )
    #endif

    // ============================== Here comes the test code:

    #include <iostream>
    using std::cout, std::endl;

    int main(void)
    {
        g_optional_obj.emplace(6);
        g_obj = 7;
        cout << g_obj << endl;
    }

Try it up on GodBolt: https://godbolt.org/z/cz96bMW5j

If we were to standardise a way of getting a "T&" from an
"optional<T>&" at compile time, then the syntax could be something
like as follows:

    std::optional<T> g_optional_obj -> g_obj;

Or perhaps avoid a change to the syntax of the core language, and
split it into two lines:

    std::optional<T> g_optional_obj;
    auto g_obj = g_optional_obj.compile_time_ref();

Or another possible syntax:

    std::optional<T> g_optional_obj;
    auto g_obj = std::optional_compile_time_ref( g_optional_obj );
--
Std-Proposals mailing list
Std-Proposals@lists.isocpp.org
https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals