Doc. no.: | WG21/N3982
Date: | 2014-04-03
Author: | Andrzej Krzemieński
Contact: | akrzemi1@gmail.com
Addresses: | fundamentals-ts

# Rvalue reference overloads for optional

This document proposes an addition of missing rvalue reference overloads for `optional` observer functions.

## Table of contents

## Motivation

Consider the following usage of `optional`. A converting function that converts from type `T` to some other type `U`:

    template <typename U, typename T>
    optional<U> convert(const T& v);

Such a conversion may fail because certain values of type `T` cannot be represented by any value of type `U`. For instance converting a `string` to `int` may fail. One user can consider such failure an exceptional condition that qualifies for a throw. Other user may just want to use a default value instead. Some other user may want to perform some fallback action, or skip some part of the code. Finally, a different user can just be sure that the conversion will not fail (e.g. when converting an `int` to a `string`), and may want to skip a time-consuming check. `optional` can satisfy all these expectations:

    int i;

    auto oi = convert<int>(str);
    if (oi) i = *oi;                    // (1) check and skip logic
    i = convert<int>(str).value_or(-1); // (2) use default
    i = convert<int>(str).value();      // (3) throw if empty
    i = *convert<int>("1");             // (4) unchecked

Now, suppose that, rather than to type `int`, we are converting to a type that is `MoveConstructible` but not `CopyConstructible`. Case (1), with manual check, does not work (unless we put an explicit `move`). But that is understandable: we want to perform two reads from the optional object: one to check if it contains the value, the other to read the value. For that we need a named object; it cannot be a temporary, so no implicit moving is possible. Case (2) will work fine. This is because function `value_or` has two overloads: for `*this` being an lvalue reference to `const` and rvalue reference. Cases (3) and (4) will not work although they could have. `optional` is just missing the rvalue reference overloads for these functions. This is what this proposal intends to fix: add rvalue reference overloads for member functions `value` and `operator*` (not for `operator->`, because it appears not to be implementable). I consider it a bug fix rather than a new feature, primarily because such an overload already exists and has been approved for function `value_or`. This is why I propose to fix it still in the first version of Fundamentals TS.

## Implementability

The proposed changes are not implementable in C++11. This is because in C++11 `constexpr` member functions automatically become `const`, and one cannot implement a member function that is both `constexpr` and has an rvalue reference qualifier. C++14 fixed it though, and a reference implementation of the proposed fix to optional in C++14 (tested in Clang 3.4) can be accessed at https://github.com/akrzemi1/Optional. For consistency, this proposal makes all the observer functions `constexpr`.

## Proposed wording

The insertions and deletions in this section describe the changes to Fundamentals TS, assuming N3966 has been incorporated.

In optional synopsis [optional.synop], change the declaration of observers as follows:

>         // 5.4.5, observers
>         constexpr T const* operator ->() const;
>         constexpr T* operator ->();
>         constexpr T const& operator *() const&;
>         constexpr T& operator *() &;
>         constexpr T&& operator *() &&;
>         constexpr explicit operator bool() const noexcept;
>         constexpr T const& value() const&;
>         constexpr T& value() &;
>         constexpr T&& value() &&;
>         template <class U> constexpr T value_or(U&&) const&;
>         template <class U> constexpr T value_or(U&&) &&;

Change [optional.object.observe] as follows:

> ##### 5.4.5 Observers [optional.object.observe]

> `constexpr T const* operator->() const;
> constexpr T* operator->();`

> Requires:

>   `bool(*this)`.

> Returns:

>   `val`.

> Throws:

>   Nothing.

> Remarks:

>   Unless `T` is a user-defined type with overloaded unary `operator&`, the first function these functions shall be a `constexpr` functions.

> `constexpr T const& operator*() const&;
> constexpr T& operator*() &;`

> Requires:

>   `bool(*this)`.

> Returns:

>   `*val`.

> Throws:

>   Nothing.

> Remarks:

>   The first function These functions shall be a `constexpr` functions.

> `constexpr T&& operator*() &&`

> Requires:

>   `bool(*this)`.

> Returns:

>   `std::move(*val)`.

> Throws:

>   Nothing.

> Remarks:

>   This function shall be a `constexpr` function.

> `constexpr explicit operator bool() noexcept;`

> Returns:

>   `true` if and only if `*this` contains a value.

> Remarks:

>   This function shall be a `constexpr` function.

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

> Returns:

>   `*val`, if `bool(*this)`.

> Throws:

>   `bad_optional_access` if `!*this`.

> Remarks:

>   The first function These functions shall be a `constexpr` functions.

> `constexpr T && value() &&;`

> Returns:

>   `std::move(*val)`, if `bool(*this)`.

> Throws:

>   `bad_optional_access` if `!*this`.

> Remarks:

>   This function shall be a `constexpr` function.

> `template <class U> constexpr T value_or(U&& v) const&;`

> Requires:

>   `is_copy_constructible<T>::value` is `true` and `is_convertible<U&&, T>::value` is `true`.

> Returns:

>   `bool(*this) ? **this : static_cast<T>(std::forward<U>(v))`.

> Throws:

>   Any exception thrown by the selected constructor of `T`.

> Exception Safety:

>   If `bool(*this)` and exception is thrown during the call to `T`'s constructor, the value of `bool(*this)` and `v` remains unchanged and the state of `*val` is determined by the exception safety guarantee of the selected constructor of `T`. Otherwise, when an exception is thrown during the call to `T`'s constructor, the value of `*this` remains unchanged and the state of `v` is determined by the exception safety guarantee of the selected constructor of `T`.

> Remarks:

>   If any of the constructors of `T` which could be selected is a `constexpr` constructor, this function shall be a `constexpr` function.

> `template <class U> constexpr T value_or(U&& v) &&;`

> Requires:

>   `is_move_constructible<T>::value` is `true` and `is_convertible<U&&, T>::value` is `true`.

> Returns:

>   `bool(*this) ? std::move(**this) : static_cast<T>(std::forward<U>(v))`.

> Throws:

>   Any exception thrown by the selected constructor of `T`.

> Exception Safety:

>   If `bool(*this)` and exception is thrown during the call to `T`'s constructor, the value of `bool(*this)` and `v` remains unchanged and the state of `*val` is determined by the exception safety guarantee of the `T`'s constructor. Otherwise, when an exception is thrown during the call to `T`'s constructor, the value of `*this` remains unchanged and the state of `v` is determined by the exception safety guarantee of the selected constructor of `T`.

> Remarks:

>   If any of the constructors of `T` which could be selected is a `constexpr` constructor, this function shall be a `constexpr` function.

## Acknowledgements

Daniel Krügler and Tomasz Kamiński reviewed the proposal and suggested fixes.