c++stdoptionalref-qualifier

What's the point of ref-qualified member functions in `std::optional::value`


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?


Solution

  • 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.