Date: Tue, 4 Jul 2023 09:10:37 +0200
Wouldn't it make more sense to have a (new) optional with a different
operator dot behavior?
n4477.pdf (open-std.org)
<https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4477.pdf>
p0252r2.pdf (open-std.org)
<https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0252r2.pdf>
This is just an other use-case why it's sad that this topic does not get
the attention it deserves.
Regards, Harald
On 2023-06-25 13:53, Frederick Virchanza Gotham via Std-Proposals 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 );
operator dot behavior?
n4477.pdf (open-std.org)
<https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4477.pdf>
p0252r2.pdf (open-std.org)
<https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0252r2.pdf>
This is just an other use-case why it's sad that this topic does not get
the attention it deserves.
Regards, Harald
On 2023-06-25 13:53, Frederick Virchanza Gotham via Std-Proposals 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 );
Received on 2023-07-04 07:10:41