2

These are the signatures, according to Cppreference:

constexpr T& value() &;
constexpr const T& value() const &;

constexpr T&& value() &&;
constexpr const T&& value() const &&;

What's the point of using &/const& and &&/const&&? Especially, I don't understand the point of having a const&& overload. const objects shouldn't be moved, so why would we have this?

BIuesky
  • 97
  • 5
  • because it's a generic template it can hold any type with any properties. So for optimizations purposes you need a way move the value out of a temporary. What exactly is your doubt? – bolov Jul 20 '23 at 23:45
  • My exact doubt is why we need an overload for `const&&`. – BIuesky Jul 20 '23 at 23:46
  • you can't know what the T object does. Because you are in a generic context you need to preserve the reference type. For instance T might have an `foo() const &&` method overload. If you don't have `optionalvalue() const&&` overload the user loses the ability to use the `T::foo() const &&` overload. – bolov Jul 21 '23 at 00:06
  • But in that case `const&` would be the preferred function, if `const&&` overload didn't exist in the first place, or am I missing your point? – BIuesky Jul 21 '23 at 00:09
  • 1
    I've written a full answer. Hope it clarifies what I mean. – bolov Jul 21 '23 at 00:17
  • From a language design perspective, I would pose two counter-questions. 1) Is there any harm (other than to your understanding) caused by having all four forms? 2) Suppose the `const&&` form was omitted; can you guarantee that no one will ever come up with a scenario where this is problematic? (In general, it is difficult to prove the non-existence of a counterexample.) – JaMiT Jul 21 '23 at 00:22
  • @JaMiT Well, 1) probably not, and 2) surely not. Good counter questions. However they don't answer the original question I guess... :P – BIuesky Jul 21 '23 at 00:29

1 Answers1

4

It's all about being in a generic template context. The standard library here needs to support all the possible scenarios (you an imagine and the ones you can't imagine) because I assure you some C++ project somewhere does use it.

So if you have a user defined type X as follows:

struct X
{
    void foo() &;          // 1
    void foo() const &;    // 2

    void foo() &&;         // 3
    void foo() const &&;   // 4
};

where foo is optimized for const temporary (foo (4)) vs const non-temporary (foo (2)) the standard library needs to support that with std::optional.

If std::optinal would be missing the constexpr const T&& value() const &&; when the user has a std::optional<X> const && (it can be in a generic template context) and tries to call foo on it the foo (2) would be called instead of foo (4).

What I mean by calling foo here:

const std::optional<X> && get_const_xvalue();
get_const_xvalue().get()foo();

// or in a generic template:

template <class Opt>
void bar(Opt&& o)
{
    std::forward<Opt>(o).get().foo();
}

// where `o` can be of type `std::optional<X> const &&`

There is a worst scenario. Imagine a user type type Y like so:

struct X
{
    void foo() &       = delete;  // 1
    void foo() const & = delete;  // 2

    void foo() &&;                // 3
    void foo() const &&;          // 4
};

In this case trying to access foo on a const temporary would result in a compiler error instead of calling the expected foo 4 overload.

bolov
  • 72,283
  • 15
  • 145
  • 224
  • I see, I thought we could just `std::move(get_const_temp().foo())` to call our foo's `const T&&` overload (so in this case `std::optional::value` overload with const T&& could be `=delete`), but in generic code that would be annoying. Thanks. Really appreciated! – BIuesky Jul 21 '23 at 00:25
  • 1
    You are welcome. Granted, const temporaries are not very useful. But as a library writter you never know what crazy pattern someone invents that uses that. – bolov Jul 21 '23 at 00:28