Date: Sun, 25 Jun 2023 12:53:06 +0100
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 );
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 );
Received on 2023-06-25 11:53:18