Doc. no.: | WG21/N3982 |
---|---|

Date: | 2014-04-03 |

Author: | Andrzej Krzemieński |

Contact: | akrzemi1@gmail.com |

Addresses: | fundamentals-ts |

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

observer functions.

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 logici = convert<int>(str).value_or(-1);// (2) use defaulti = convert<int>(str).value();// (3) throw if emptyi = *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.

`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`

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

Change [optional.object.observe] as follows://5.4.5, observersconstexpr 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&&) &&;

## 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:

`, if`

*val`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(`

, if*val)`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`remains unchanged and the state of`

v`is determined by the exception safety guarantee of the selected constructor of`

*val`T`

. Otherwise, when an exception is thrown during the call to`T`

's constructor, the value of`remains unchanged and the state of`

*this`is determined by the exception safety guarantee of the selected constructor of`

v`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`remains unchanged and the state of`

v`is determined by the exception safety guarantee of the`

*val`T`

's constructor. Otherwise, when an exception is thrown during the call to`T`

's constructor, the value of`remains unchanged and the state of`

*this`is determined by the exception safety guarantee of the selected constructor of`

v`T`

.- Remarks:
If any of the constructors of

`T`

which could be selected is a`constexpr`

constructor, this function shall be a`constexpr`

function.

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