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