ISO/IEC JTC1 SC22 WG21 N3966 2014-03-01

Fernando Cacciola, fernando.cacciola@gmail.com Andrzej Krzemieński, akrzemi1@gmail.comProject: Programming Language C++, fundamentals-ts

This document proposes a number of wording fixes, as suggested in Issaquah meeting, to optional objects proposed in N3793. We do not propose any changes in the functionality. We only reworded the standardese, and applied bug fixes:

- Got rid of terms 'engaged' and 'disengaged'; now using term 'contains a value' instead.
- Using term 'direct-non-list-initialization'; it was missing in a number of places.
- Now using alias template
`decay_t`

in place of the old type trait. - Changed the conditions under which function
`value_or`

shall be`costexpr`

. - Fixed spelling and grammar mistakes.

The insertions and deletions in this section describe the changes to Fundamentals TS after applying the changes from N3793. In other words, the changes are relative to N3793.

Change [optional.synop]://5.5, In-place constructionstruct in_place_t{}; constexpr in_place_t in_place{}; //5.6,struct nullopt_t{~~Disengaged~~No-value state indicatorsee below}; constexpr nullopt_t nullopt(unspecified); //5.7, class bad_optional_accessclass bad_optional_access;

Replace [optional.object], para 1 and 2 with the followingprivate:bool init; //exposition onlyT* val; //exposition only};

Any instance of

`optional<T>`

at any given time can eithercontain a valueornot contain a value. When an instance of`optional<T>`

contains a value, it means that an object of type`T`

, referred to as the optional object'scontained value, is allocated within the storage of the optional object. Implementations are not permitted to use additional storage, such as dynamic memory, to allocate its contained value. The contained value shall be allocated in a region of the`optional<T>`

storage suitably aligned for the type`T`

. When an instance of`optional<T>`

contains a value, its contextual conversion to`bool`

returns`true`

; otherwise it returns`false`

.

Member`is provided for exposition only. When an optional object contains a value`

val`points to the contained value.`

val

Change [optional.object] subclauses as follows:

## 5.4.1 Constructors [optional.object.ctor]

`constexpr optional<T>::optional() noexcept;`

`constexpr optional<T>::optional(nullopt_t) noexcept;`

- Postconditions:

`*this`

is disengaged`!*this`

.- Remarks:
No contained value is initialized. For every object type

`T`

these constructors shall be`constexpr`

constructors (C++11 §7.1.5).

`optional<T>::optional(const optional<T>&`

rhs);

- Requires:

`is_copy_constructible<T>::value`

is`true`

.- Effects:
If

`bool(`

rhs)~~is engaged~~initializes the contained value as if direct-non-list-initializing an object of type`T`

with the expression`*`

.rhs- Postconditions:

`bool(`

.rhs) == bool(*this)- Throws:
Any exception thrown by the selected constructor of

`T`

.

`optional<T>::optional(optional<T> &&`

rhs) noexcept(see below);

- Requires:

`is_move_constructible<T>::value`

is`true`

.- Effects:
If

`bool(`

rhs)~~is engaged~~initializes the contained value as if direct-non-list-initializing an object of type`T`

with the expression`std::move(*`

.rhs)`bool(`

is unchanged.rhs)- Postconditions:

`bool(`

.rhs) == bool(*this)- Throws:
Any exception thrown by the selected constructor of

`T`

.- Remarks:
The expression inside

`noexcept`

is equivalent to:is_nothrow_move_constructible<T>::value

`constexpr optional<T>::optional(const T&`

v);

- Requires:

`is_copy_constructible<T>::value`

is`true`

.- Effects:
Initializes the contained value as if direct-non-list-initializing an object of type

`T`

with the expression`.`

v- Postconditions:

`bool(*this)`

~~is engaged~~.- Throws:
Any exception thrown by the selected constructor of

`T`

.- Remarks:
If

`T`

's selected constructor is a`constexpr`

constructor, this constructor shall be a`constexpr`

constructor.

`constexpr optional<T>::optional(T&&`

v);

- Requires:

`is_move_constructible<T>::value`

is`true`

.- Effects:
Initializes the contained value as if direct-non-list-initializing an object of type

`T`

with the expression`std::move(`

.v)- Postconditions:

`bool(*this)`

~~is engaged~~.- Throws:
Any exception thrown by the selected constructor of

`T`

.- Remarks:
If

`T`

's selected constructor is a`constexpr`

constructor, this constructor shall be a`constexpr`

constructor.

`template <class... Args> constexpr explicit optional(in_place_t, Args&&...`

args);

- Requires:

`is_constructible<T, Args&&...>::value`

is`true`

.- Effects:
Initializes the contained value as if direct-non-list-initializing an object of type

`T`

with the arguments`std::forward<Args>(`

.args)...- Postconditions:

`bool(*this)`

~~is engaged~~.- Throws:
Any exception thrown by the selected constructor of

`T`

.- Remarks:
If

`T`

's constructor selected for the initialization is a`constexpr`

constructor, this constructor shall be a`constexpr`

constructor.

`template <class U, class... Args>`

constexpr explicit optional(in_place_t, initializer_list<U>il, Args&&...args);

- Requires:

`is_constructible<T, initializer_list<U>&, Args&&...>::value`

is`true`

.- Effects:
Initializes the contained value as if direct-non-list-initializing an object of type

`T`

with the arguments`.`

il, std::forward<Args>(args)...- Postconditions:

`bool(*this)`

~~is engaged~~.- Throws:
Any exception thrown by the selected constructor of

`T`

.- Remarks:
The function shall not participate in overload resolution unless

`is_constructible<T, initializer_list<U>&, Args&&...>::value`

is`true`

.- Remarks:
If

`T`

's constructor selected for the initialization is a`constexpr`

constructor, this constructor shall be a`constexpr`

constructor.## 5.4.2 Destructor [optional.object.dtor]

`optional<T>::~optional();`

- Effects:
If

`is_trivially_destructible<T>::value != true`

and`bool(*this)`

~~is engaged~~, calls`.`

val->T::~T()- Remarks:
If

`is_trivially_destructible<T>::value == true`

then this destructor shall be a trivial destructor.## 5.4.3 Assignment [optional.object.assign]

`optional<T>& optional<T>::operator=(nullopt_t) noexcept;`

- Effects:
If

`bool(*this)`

~~is engaged~~calls`to destroy the contained value; otherwise no effect.`

val->T::~T()- Returns:

`*this`

.- Postconditions:

`!*this`

~~is disengaged~~.

`optional<T>& optional<T>::operator=(const optional<T>&`

rhs);

- Requires:

`is_copy_constructible<T>::value`

is`true`

and`is_copy_assignable<T>::value`

is`true`

.- Effects:

- If
`*this`

is disengaged and`is disengaged`

rhs`!*this && !`

, no effect, otherwiserhs- if
`*this`

is engaged and`is disengaged`

rhs`bool(*this) && !`

, destroys the contained value by callingrhs`, otherwise`

val->T::~T()- if
`*this`

is disengaged and`is engaged`

rhs`!*tis && bool(`

, initializes the contained value as if direct-non-list-initializing an object of typerhs)`T`

with`*`

, otherwiserhs- (if
~~both~~`*this`

and`are engaged`

rhs`bool(*this) && bool(`

) assignsrhs)`*`

to the contained value.rhs- Returns:

`*this`

.- Postconditions:

`bool(`

.rhs) == bool(*this)- Exception Safety:
If any exception is thrown, the values

`bool(*this)`

and`bool(`

rhs)~~of~~remain unchanged. If an exception is thrown during the call to`and`

init

rhs.init`T`

's copy constructor, no effect. If an exception is thrown during the call to`T`

's copy assignment, the state of its contained value is as defined by the exception safety guarantee of`T`

's copy assignment.

`optional<T>& optional<T>::operator=(optional<T>&&`

rhs) noexcept(see below);

- Requires:

`is_move_constructible<T>::value`

is`true`

and`is_move_assignable<T>::value`

is`true`

.- Effects:

- If
`*this`

is disengaged and`is disengaged`

rhs`!*this && !`

, no effect, otherwiserhs- if
`*this`

is engaged and`is disengaged`

rhs`bool(*this) && !`

, destroys the contained value by callingrhs`, otherwise`

val->T::~T()- if
`*this`

is disengaged and`is engaged`

rhs`!*tis && bool(`

, initializes the contained value as if direct-non-list-initializing an object of typerhs)`T`

with`std::move(*`

, otherwiserhs)- (if
~~both~~`*this`

and`are engaged`

rhs`bool(*this) && bool(`

) assignsrhs)`std::move(*`

to the contained value.rhs)- Returns:

`*this`

.- Postconditions:

`bool(`

.rhs) == bool(*this)- Remarks:
The expression inside

`noexcept`

is equivalent to:is_nothrow_move_assignable<T>::value && is_nothrow_move_constructible<T>::value- Exception Safety:
If any exception is thrown, the values

`bool(*this)`

and`bool(`

rhs)~~of~~remain unchanged. If an exception is thrown during the call to`and`

init

rhs.init`T`

's move constructor, the state of`*rhs.val`

is determined by exception safety guarantee of`T`

's move constructor. If an exception is thrown during the call to`T`

's move assignment, the state of`and`

*val`*rhs.val`

is determined by exception safety guarantee of`T`

's move assignment.

`template <class U> optional<T>& optional<T>::operator=(U&&`

v);

- Requires:

`is_constructible<T, U>::value`

is`true`

and`is_assignable<T&, U>::value`

is`true`

.- Effects:
If

`bool(*this)`

~~is engaged~~assigns`std::forward<U>(`

to the contained value; otherwise initializes the contained value as if direct-non-list-initializing object of typev)`T`

with`std::forward<U>(`

.v)- Returns:

`*this`

.- Postconditions:

`bool(*this)`

~~is engaged~~.- Exception Safety:
If any exception is thrown, value

`bool(*this)`

~~of~~remains unchanged. If an exception is thrown during the call to

init`T`

's constructor, the state of`is determined by exception safety guarantee of`

v`T`

's constructor. If an exception is thrown during the call to`T`

's assignment, the state of`and`

*val`is determined by exception safety guarantee of`

v`T`

's assignment.- Remarks:
The function shall not participate in overload resolution unless

`is_same<`

is~~typename decay<U>::type~~decay_t<U>, T>::value`true`

.[

Note:The reason to provide such generic assignment and then constraining it so that effectively`T`

==`U`

is to guarantee that assignment of the form`o = {}`

is unambiguous. —end note]

`template <class... Args> void optional<T>::emplace(Args&&...`

args);

- Requires:

`is_constructible<T, Args&&...>::value`

is`true`

.- Effects:
Calls

`*this = nullopt`

. Then initializes the contained value as if~~constructing~~direct-non-list-initializing an object of type`T`

with the arguments`std::forward<Args>(`

.args)...- Postconditions:

`bool(*this)`

~~is engaged~~.- Throws:
Any exception thrown by the selected constructor of

`T`

.- Exception Safety:
If an exception is thrown during the call to

`T`

's constructor,`*this`

~~is disengaged~~does not contain a value, and the previous`(if any) has been destroyed.`

*val

`template <class U, class... Args> void optional<T>::emplace(initializer_list<U>`

il, Args&&...args);

- Requires:

`is_constructible<T, initializer_list<U>&, Args&&...>::value`

is`true`

.- Effects:
Calls

`*this = nullopt`

. Then initializes the contained value as if~~constructing~~direct-non-list-initializing an object of type`T`

with the arguments`.`

il, std::forward<Args>(args)...- Postconditions:

`bool(*this)`

~~is engaged~~.- Throws:
Any exception thrown by the selected constructor of

`T`

.- Exception Safety:
If an exception is thrown during the call to

`T`

's constructor,`*this`

~~is disengaged~~does not contain a value, and the previous`(if any) has been destroyed.`

*val- Remarks:
The function shall not participate in overload resolution unless

`is_constructible<T, initializer_list<U>&, Args&&...>::value`

is`true`

.## 5.4.4 Swap [optional.object.swap]

`void optional<T>::swap(optional<T>& rhs) noexcept(`

see below);

- Requires:
L~~V~~values of type T shall be swappable and`is_move_constructible<T>::value`

is`true`

.- Effects:

- If
`*this`

is disengaged and`is disengaged`

rhs`!*this && !`

, no effect, otherwiserhs- if
`*this`

is engaged and`is disengaged`

rhs`bool(*this) && !`

, initializes the contained value ofrhs

rhs~~by direct-initialization~~as if direct-non-list-initializing an object of type`T`

with the expression`std::move(*(*this))`

, followed by`val->T::~T()`

,~~, swap(~~init,rhs.init)`*this`

does not contain a value and`contains a value, otherwise`

rhs- if
`*this`

is disengaged and`is engaged`

rhs`!*tis && bool(`

, initializes the contained value ofrhs)`*this`

~~by direct-initialization~~as if direct-non-list-initializing an object of type`T`

with the expression`std::move(*`

, followed byrhs)`rhs.val->T::~T()`

,~~, swap(~~init,rhs.init)`*this`

contains a value and`does not contain a value, otherwise`

rhs- (if
~~both~~`*this`

and`are engaged`

rhs`bool(*this) && bool(`

) callsrhs)`swap(*(*this), *`

.rhs)- Throws:
Any exceptions that the expressions in the Effects clause throw.

- Remarks:
The expression inside

`noexcept`

is equivalent to:is_nothrow_move_constructible<T>::value && noexcept(swap(declval<T&>(), declval<T&>()))- Exception Safety:
If any exception is thrown, values

~~of~~`and`

init

rhs.init`bool(*this)`

and`bool(`

remain unchanged. If an exception is thrown during the call to functionrhs)`swap`

the state of`and`

*val`*rhs.val`

is determined by the exception safety guarantee of`swap`

for lvalues of`T`

. If an exception is thrown during the call to`T`

's move constructor, the state of`and`

*val`*rhs.val`

is determined by the exception safety guarantee of`T`

's move constructor.## 5.4.5 Observers [optional.object.observe]

`constexpr T const* optional<T>::operator->() const;`

T* optional<T>::operator->();

- Requires:

`bool(*this)`

~~is engaged~~.- Returns:

`.`

val- Throws:
Nothing.

- Remarks:
Unless

`T`

is a user-defined type with overloaded unary`operator&`

, the first function shall be a`constexpr`

function.

`constexpr T const& optional<T>::operator*() const;`

T& optional<T>::operator*();

- Requires:

`bool(*this)`

~~is engaged~~- Returns:

`*`

.val- Throws:
Nothing.

- Remarks:
The first function shall be a

`constexpr`

function.

`constexpr explicit optional<T>::operator bool() noexcept;`

- Returns:

init`true`

if and only if`*this`

contains a value.- Remarks:
This function shall be a

`constexpr`

function.

`constexpr T const& optional<T>::value() const;`

T& optional<T>::value();

- Returns:

`, if`

*val`bool(*this)`

.- Throws:

`bad_optional_access`

if`!*this`

.- Remarks:
The first function shall be a

`constexpr`

function.

`template <class U> constexpr T optional<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

init== true`bool(*this)`

and exception is thrown during the call to`T`

's constructor, the value of

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

~~both~~any of the constructors of`T`

which could be selected~~are~~is a`constexpr`

constructor~~s~~, this function shall be a`constexpr`

function.

`template <class U> T optional<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

init== true`bool(*this)`

and exception is thrown during the call to`T`

's constructor, the value of

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

.## 5.5 In-place construction [optional.inplace]

`struct in_place_t{};`

constexpr in_place_t in_place{};The struct

`in_place_t`

is an empty structure type used as a unique type to disambiguate constructor and function overloading. Specifically,`optional<T>`

has a constructor with`in_place_t`

as the first argument followed by an argument pack; this indicates that`T`

should be constructed in-place (as if by a call to placement new expression) with the forwarded argument pack as parameters.## 5.6

~~Disengaged~~No-value state indicator [optional.nullopt]

`struct nullopt_t{`

see below};

constexpr nullopt_t nullopt(unspecified);The struct

`nullopt_t`

is an empty structure type used as a unique type to indicate~~a disengaged state~~the state of not containing a value for`optional`

objects. In particular,`optional<T>`

has a constructor with`nullopt_t`

as single argument; this indicates that an~~disengaged~~optional object not containing a value shall be constructed.Type

`nullopt_t`

shall not have a default constructor. It shall be a literal type. Constant`nullopt`

shall be initialized with an argument of literal type.## 5.7 Class

`bad_optional_access`

[optional.bad_optional_access]namespace std { class bad_optional_access : public logic_error { public: explicit bad_optional_access(const string& what_arg); explicit bad_optional_access(const char* what_arg); }; }The class

`bad_optional_access`

defines the type of objects thrown as exceptions to report the situation where an attempt is made to access the value of an~~disengaged~~optional object that does not contain a value.

`bad_optional_access(const string& what_arg);`

- Effects:
Constructs an object of class

`bad_optional_access`

.- Postcondition:

`strcmp(what(), what_arg.c_str()) == 0`

.

`bad_optional_access(const char* what_arg);`

- Effects:
Constructs an object of class

`bad_optional_access`

.- Postcondition:

`strcmp(what(), what_arg) == 0`

.

Change [optional.relops] as follows:

## 5.8 Relational operators [optional.relops]

`template <class T> constexpr bool operator==(const optional<T>& x, const optional<T>& y);`

- Requires:

`T`

shall meet the requirements of`EqualityComparable`

.- Returns:
If

`bool(x) != bool(y)`

,`false`

; otherwise if`bool(x) == false`

,`true`

; otherwise`*x == *y`

.- Remarks:
Instantiations of this function template for which

`*x == *y`

is a core constant expression, shall be`constexpr`

functions.

`template <class T> constexpr bool operator!=(const optional<T>& x, const optional<T>& y);`

- Returns:

`!(x == y)`

.

`template <class T> constexpr bool operator<(const optional<T>&`

x, const optional<T>&y);

- Requires:

~~Expression~~`*`

shall be well-formed and its result shall be convertible tox< *y`bool`

.- Returns:
If

`(!`

,y)`false`

; otherwise, if`(!`

,x)`true`

; otherwise`*`

.x< *y- Remarks:
Instantiations of this function template for which expression

`*`

is a core constant expression, shall bex< *y`constexpr`

functions.

Change [optional.nullops] as follows:

## 5.9 Comparison with

`nullopt`

[optional.nullops]

`template <class T> constexpr bool operator==(const optional<T>&`

x, nullopt_t) noexcept;

template <class T> constexpr bool operator==(nullopt_t, const optional<T>& x) noexcept;

- Returns:

`.`

~~(~~!x~~)~~

`template <class T> constexpr bool operator!=(const optional<T>&`

x, nullopt_t) noexcept;

template <class T> constexpr bool operator!=(nullopt_t, const optional<T>& x) noexcept;

- Returns:

`bool(`

.x)

`template <class T> constexpr bool operator<(const optional<T>&`

x, nullopt_t) noexcept;

- Returns:

`false`

.

`template <class T> constexpr bool operator<(nullopt_t, const optional<T>&`

x) noexcept;

- Returns:

`bool(`

.x)

`template <class T> constexpr bool operator<=(const optional<T>&`

x, nullopt_t) noexcept;

- Returns:

`.`

~~(~~!x~~)~~

`template <class T> constexpr bool operator<=(nullopt_t, const optional<T>&`

x) noexcept;

- Returns:

`true`

.

`template <class T> constexpr bool operator>(const optional<T>&`

x, nullopt_t) noexcept;

- Returns:

`bool(`

.x)

`template <class T> constexpr bool operator>(nullopt_t, const optional<T>&`

x) noexcept;

- Returns:

`false`

.

`template <class T> constexpr bool operator>=(const optional<T>&`

x, nullopt_t) noexcept;

- Returns:

`true`

.

`template <class T> constexpr bool operator>=(nullopt_t, const optional<T>&`

x) noexcept;

- Returns:

`.`

~~(~~!x~~)~~

Jonathan Wakely reviewed the proposal and offered useful suggestions.

Daniel Krügler provided numerous helpful suggestions, corrections and comments on this proposal; in particular he suggested the addition of and reference implementation for "perfect initialization" operations.

Many people from the Boost community, participated in the developement of the Boost.Optional library. Sebastian Redl suggested the usage of function `emplace`

.

Tony Van Eerd offered many useful suggestions and corrections to the proposal.

People in discussion group "ISO C++ Standard - Future Proposals" provided numerous insightful suggestions: Vladimir Batov (who described and supported the perfect forwarding constructor), Nevin Liber, Ville Voutilainen, Richard Smiths, Dave Abrahams, Chris Jefferson, Jeffrey Yasskin, Nikolay Ivchenkov, Matias Capeletto, Olaf van der Spek, Vincent Jacquet, Kazutoshi Satoda, Vicente J. Botet Escriba, Róbert Dávid, Vincent Jacquet, Luc Danton, Greg Marr, and many more.

Joe Gottman suggested the support for hashing some optional objects.

Nicol Bolas suggested to make `operator->`

conditionally `constexpr`

based on whether `T::operator&`

is overloaded.