23 General utilities library [utilities]

23.6 Optional objects [optional]

23.6.3 Class template optional [optional.optional]

template <class T>
  class optional {
  public:
    using value_type = T;

    // [optional.ctor], constructors
    constexpr optional() noexcept;
    constexpr optional(nullopt_t) noexcept;
    constexpr optional(const optional&);
    constexpr optional(optional&&) noexcept(see below);
    template <class... Args>
      constexpr explicit optional(in_place_t, Args&&...);
    template <class U, class... Args>
      constexpr explicit optional(in_place_t, initializer_list<U>, Args&&...);
    template <class U = T>
      EXPLICIT constexpr optional(U&&);
    template <class U>
      EXPLICIT optional(const optional<U>&);
    template <class U>
      EXPLICIT optional(optional<U>&&);

    // [optional.dtor], destructor
    ~optional();

    // [optional.assign], assignment
    optional& operator=(nullopt_t) noexcept;
    optional& operator=(const optional&);
    optional& operator=(optional&&) noexcept(see below);
    template <class U = T> optional& operator=(U&&);
    template <class U> optional& operator=(const optional<U>&);
    template <class U> optional& operator=(optional<U>&&);
    template <class... Args> T& emplace(Args&&...);
    template <class U, class... Args> T& emplace(initializer_list<U>, Args&&...);

    // [optional.swap], swap
    void swap(optional&) noexcept(see below);

    // [optional.observe], observers
    constexpr const T* operator->() const;
    constexpr T* operator->();
    constexpr const T& operator*() const&;
    constexpr T& operator*() &;
    constexpr T&& operator*() &&;
    constexpr const T&& operator*() const&&;
    constexpr explicit operator bool() const noexcept;
    constexpr bool has_value() const noexcept;
    constexpr const T& value() const&;
    constexpr T& value() &;
    constexpr T&& value() &&;
    constexpr const T&& value() const&&;
    template <class U> constexpr T value_or(U&&) const&;
    template <class U> constexpr T value_or(U&&) &&;

    // [optional.mod], modifiers
    void reset() noexcept;

  private:
    T *val; // exposition only
  };

template<class T> optional(T) -> optional<T>;

Любой экземпляр optional<T> в любой момент времени либо содержит значение, либо не содержит значения. Когда является экземпляром optional<T> contains a value, это означает, что объект типа T, называемый необязательным объектом contained value, размещается в хранилище необязательного объекта. Реализациям не разрешается использовать дополнительное хранилище, такое как динамическая память, для выделения содержащегося в нем значения. Содержимое значение должно быть размещено в области optional<T> памяти, соответствующей типу T. Когда объект типа optional<T> контекстно преобразуется в bool, преобразование возвращается, true если объект содержит значение; в противном случае преобразование вернется false.

Участник val предназначен только для экспозиции. Когда optional<T> объект содержит значение, val указывает на содержащееся значение.

T должен быть типом объекта и удовлетворять требованиям Destructible.

23.6.3.1 Constructors [optional.ctor]

constexpr optional() noexcept; constexpr optional(nullopt_t) noexcept;

Postconditions: *this не содержит значения.

Remarks: Никакое содержащееся значение не инициализируется. Для каждого типа объекта T эти конструкторы должны быть constexpr constructors.

constexpr optional(const optional& rhs);

Effects: Если rhs содержит значение, инициализирует содержащееся значение, как если бы инициализирует объект типа T выражением напрямую без использования списка *rhs.

Postconditions: bool(rhs) == bool(*this).

Throws: Любое исключение, созданное выбранным конструктором T.

Remarks: Этот конструктор должен быть определен как удален , если is_­copy_­constructible_­v<T> не true. Если is_­trivially_­copy_­constructible_­v<T> есть true, этот конструктор должен быть constexpr конструктором.

constexpr optional(optional&& rhs) noexcept(see below);

Effects: Если rhs содержит значение, инициализирует содержащееся значение, как если бы инициализирует объект типа T выражением напрямую без использования списка std​::​move(*rhs). bool(rhs) без изменений.

Postconditions: bool(rhs) == bool(*this).

Throws: Любое исключение, созданное выбранным конструктором T.

Remarks: Выражение внутри noexcept эквивалентно is_­nothrow_­move_­constructible_­v<T>. Этот конструктор не должен участвовать в разрешении перегрузки , если is_­move_­constructible_­v<T> не true. Если is_­trivially_­move_­constructible_­v<T> есть true, этот конструктор должен быть constexpr конструктором.

template <class... Args> constexpr explicit optional(in_place_t, Args&&... args);

Effects: Инициализирует содержащееся значение, как если бы инициализирует объект типа напрямую без использования списка T с аргументами std​::​forward<Args>(args)....

Postconditions: *this содержит значение.

Throws: Любое исключение, созданное выбранным конструктором T.

Remarks: Если Tконструктор, выбранный для инициализации, является конструктором constexpr, этот конструктор должен быть конструктором constexpr. Этот конструктор не должен участвовать в разрешении перегрузки , если is_­constructible_­v<T, Args...> не true.

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

Effects: Инициализирует содержащееся значение, как если бы инициализирует объект типа напрямую без использования списка T с аргументами il, std​::​forward<Args>(args)....

Postconditions: *this содержит значение.

Throws: Любое исключение, созданное выбранным конструктором T.

Remarks: Этот конструктор не должен участвовать в разрешении перегрузки , если is_­constructible_­v<T, initializer_­list<U>&, Args&&...> не true. Если Tконструктор, выбранный для инициализации, является конструктором constexpr, этот конструктор должен быть конструктором constexpr.

[ Note: Следующие конструкторы условно указаны как явные. Обычно это реализуется путем объявления двух таких конструкторов, максимум один из которых участвует в разрешении перегрузки. ]end note

template <class U = T> EXPLICIT constexpr optional(U&& v);

Effects: Инициализирует содержащееся значение, как если бы инициализирует объект типа напрямую, не являясь списком, T с выражением std​::​forward<U>(v).

Postconditions: *this содержит значение.

Throws: Любое исключение, созданное выбранным конструктором T.

Remarks: Если Tвыбранный конструктор является конструктором constexpr, этот конструктор должен быть конструктором constexpr. Этот конструктор не должен участвовать в разрешении перегрузки, за исключением случаев, когда is_­constructible_­v<T, U&&> есть true, is_­same_­v<decay_­t<U>, in_­place_­t> есть falseи is_­same_­v<optional<T>, decay_­t<U>> есть false. Конструктор является явным тогда и только тогда, когда он is_­convertible_­v<U&&, T> есть false.

template <class U> EXPLICIT optional(const optional<U>& rhs);

Effects: Если rhs содержит значение, инициализирует содержащееся значение, как если бы инициализирует объект типа T выражением напрямую без использования списка *rhs.

Postconditions: bool(rhs) == bool(*this).

Throws: Любое исключение, созданное выбранным конструктором T.

Remarks: Этот конструктор не должен участвовать в разрешении перегрузки, если только

  • is_­constructible_­v<T, const U&> есть true,

  • is_­constructible_­v<T, optional<U>&> есть false,

  • is_­constructible_­v<T, optional<U>&&> есть false,

  • is_­constructible_­v<T, const optional<U>&> есть false,

  • is_­constructible_­v<T, const optional<U>&&> есть false,

  • is_­convertible_­v<optional<U>&, T> есть false,

  • is_­convertible_­v<optional<U>&&, T> есть false,

  • is_­convertible_­v<const optional<U>&, T> есть false, и

  • is_­convertible_­v<const optional<U>&&, T> есть false.

Конструктор является явным тогда и только тогда, когда он is_­convertible_­v<const U&, T> есть false.

template <class U> EXPLICIT optional(optional<U>&& rhs);

Effects: Если rhs содержит значение, инициализирует содержащееся значение, как если бы инициализирует объект типа T выражением напрямую без использования списка std​::​move(*rhs). bool(rhs) без изменений.

Postconditions: bool(rhs) == bool(*this).

Throws: Любое исключение, созданное выбранным конструктором T.

Remarks: Этот конструктор не должен участвовать в разрешении перегрузки, если только

  • is_­constructible_­v<T, U&&> правда,

  • is_­constructible_­v<T, optional<U>&> есть false,

  • is_­constructible_­v<T, optional<U>&&> есть false,

  • is_­constructible_­v<T, const optional<U>&> есть false,

  • is_­constructible_­v<T, const optional<U>&&> есть false,

  • is_­convertible_­v<optional<U>&, T> есть false,

  • is_­convertible_­v<optional<U>&&, T> есть false,

  • is_­convertible_­v<const optional<U>&, T> есть false, и

  • is_­convertible_­v<const optional<U>&&, T> есть false.

Конструктор является явным тогда и только тогда, когда он is_­convertible_­v<U&&, T> есть false.

23.6.3.2 Destructor [optional.dtor]

~optional();

Effects: Если is_­trivially_­destructible_­v<T> != true и *this содержит значение, вызывает

val->T::~T()

Remarks: Если is_­trivially_­destructible_­v<T> == true тогда этот деструктор должен быть тривиальным деструктором.

23.6.3.3 Assignment [optional.assign]

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

Effects: Если *this содержит значение, вызывает val->T​::​~T() уничтожение содержащегося значения; в остальном никакого эффекта.

Returns: *this.

Postconditions: *this не содержит значения.

optional<T>& operator=(const optional& rhs);

Effects: См. Таблицу 35.

Таблица 35 - optional​::​operator=(const optional&) эффекты
*this содержит значение*this не содержит значения
rhs содержит значение присваивает *rhs содержащееся значение инициализирует значение , содержащееся как если прямая не-список-инициализацию объекта типа T с *rhs
rhs не содержит значения уничтожает содержащееся значение, вызывая val->T​::​~T() нет эффекта

Returns: *this.

Postconditions: bool(rhs) == bool(*this).

Remarks: Если возникает какое-либо исключение, результат выражения bool(*this) остается неизменным. Если во время вызова Tконструктора копирования возникает исключение , никакого эффекта. Если во время вызова Tприсваивания копии возникает исключение , состояние содержащегося в нем значения определяется гарантией безопасности исключений Tприсваивания копии. Этот оператор должен быть определен как удален , если is_­copy_­constructible_­v<T> не true и is_­copy_­assignable_­v<T> является true.

optional<T>& operator=(optional&& rhs) noexcept(see below);

Effects: См. Таблицу 36. Результат выражения bool(rhs) остается неизменным.

Таблица 36 - optional​::​operator=(optional&&) эффекты
*this содержит значение*this не содержит значения
rhs содержит значение присваивает std​::​move(*rhs) содержащееся значение инициализирует значение , содержащееся как если прямая не-список-инициализацию объекта типа T с std​::​move(*rhs)
rhs не содержит значения уничтожает содержащееся значение, вызывая val->T​::​~T() нет эффекта

Returns: *this.

Postconditions: bool(rhs) == bool(*this).

Remarks: Выражение внутри noexcept эквивалентно:

is_nothrow_move_assignable_v<T> && is_nothrow_move_constructible_v<T>

Если возникает какое-либо исключение, результат выражения bool(*this) остается неизменным. Если во время вызова Tконструктора перемещения возникает исключение , состояние *rhs.val определяется гарантией безопасности исключений Tконструктора перемещения. Если во время вызова Tприсваивания перемещения возникает исключение , состояние *val и *rhs.val определяется гарантией безопасности исключения Tприсваивания перемещения. Этот оператор не должен участвовать в разрешении перегрузки , если is_­move_­constructible_­v<T> не true и is_­move_­assignable_­v<T> является true.

template <class U = T> optional<T>& operator=(U&& v);

Effects: Если *this содержит значение, присваивается std​::​forward<U>(v) содержащемуся значению; в противном случае инициализирует значение , содержащееся как если прямой не-список-инициализацию объекта типа T с std​::​forward<U>(v).

Returns: *this.

Postconditions: *this содержит значение.

Remarks: Если возникает какое-либо исключение, результат выражения bool(*this) остается неизменным. Если во время вызова Tконструктора возникает исключение , состояние v определяется гарантией безопасности исключений Tконструктора. Если во время вызова Tприсваивания вызывается исключение , состояние *val и v определяется гарантией безопасности исключений Tприсваивания. Эта функция не должна участвовать в разрешении перегрузки, за исключением случаев, когда is_­same_­v<optional<T>, decay_­t<U>> есть false, conjunction_­v<is_­scalar<T>, is_­same<T, decay_­t<U>>> есть false, is_­constructible_­v<T, U> есть trueи is_­assignable_­v<T&, U> есть true.

template <class U> optional<T>& operator=(const optional<U>& rhs);

Effects: См. Таблицу 37.

Таблица 37 - optional​::​operator=(const optional<U>&) эффекты
*this содержит значение*this не содержит значения
rhs содержит значение присваивает *rhs содержащееся значение инициализирует значение , содержащееся как если прямая не-список-инициализацию объекта типа T с *rhs
rhs не содержит значения уничтожает содержащееся значение, вызывая val->T​::​~T() нет эффекта

Returns: *this.

Postconditions: bool(rhs) == bool(*this).

Remarks: Если возникает какое-либо исключение, результат выражения bool(*this) остается неизменным. Если во время вызова Tконструктора возникает исключение , состояние *rhs.val определяется гарантией безопасности исключений Tконструктора. Если во время вызова Tприсваивания вызывается исключение , состояние *val и *rhs.val определяется гарантией безопасности исключений Tприсваивания. Эта функция не должна участвовать в разрешении перегрузки, если только

  • is_­constructible_­v<T, const U&> есть true,

  • is_­assignable_­v<T&, const U&> есть true,

  • is_­constructible_­v<T, optional<U>&> есть false,

  • is_­constructible_­v<T, optional<U>&&> есть false,

  • is_­constructible_­v<T, const optional<U>&> есть false,

  • is_­constructible_­v<T, const optional<U>&&> есть false,

  • is_­convertible_­v<optional<U>&, T> есть false,

  • is_­convertible_­v<optional<U>&&, T> есть false,

  • is_­convertible_­v<const optional<U>&, T> есть false,

  • is_­convertible_­v<const optional<U>&&, T> есть false,

  • is_­assignable_­v<T&, optional<U>&> есть false,

  • is_­assignable_­v<T&, optional<U>&&> есть false,

  • is_­assignable_­v<T&, const optional<U>&> есть false, и

  • is_­assignable_­v<T&, const optional<U>&&> есть false.

template <class U> optional<T>& operator=(optional<U>&& rhs);

Effects: См. Таблицу 38. Результат выражения bool(rhs) остается неизменным.

Таблица 38 - optional​::​operator=(optional<U>&&) эффекты
*this содержит значение*this не содержит значения
rhs содержит значение присваивает std​::​move(*rhs) содержащееся значение инициализирует значение , содержащееся как если прямая не-список-инициализацию объекта типа T с std​::​move(*rhs)
rhs не содержит значения уничтожает содержащееся значение, вызывая val->T​::​~T() нет эффекта

Returns: *this.

Postconditions: bool(rhs) == bool(*this).

Remarks: Если возникает какое-либо исключение, результат выражения bool(*this) остается неизменным. Если во время вызова Tконструктора возникает исключение , состояние *rhs.val определяется гарантией безопасности исключений Tконструктора. Если во время вызова Tприсваивания вызывается исключение , состояние *val и *rhs.val определяется гарантией безопасности исключений Tприсваивания. Эта функция не должна участвовать в разрешении перегрузки, если только

  • is_­constructible_­v<T, U> есть true,

  • is_­assignable_­v<T&, U> есть true,

  • is_­constructible_­v<T, optional<U>&> есть false,

  • is_­constructible_­v<T, optional<U>&&> есть false,

  • is_­constructible_­v<T, const optional<U>&> есть false,

  • is_­constructible_­v<T, const optional<U>&&> есть false,

  • is_­convertible_­v<optional<U>&, T> есть false,

  • is_­convertible_­v<optional<U>&&, T> есть false,

  • is_­convertible_­v<const optional<U>&, T> есть false,

  • is_­convertible_­v<const optional<U>&&, T> есть false,

  • is_­assignable_­v<T&, optional<U>&> есть false,

  • is_­assignable_­v<T&, optional<U>&&> есть false,

  • is_­assignable_­v<T&, const optional<U>&> есть false, и

  • is_­assignable_­v<T&, const optional<U>&&> есть false.

template <class... Args> T& emplace(Args&&... args);

Requires: is_­constructible_­v<T, Args&&...> есть true.

Effects: Звонки *this = nullopt. Затем инициализирует содержащееся значение, как если бы инициализирует объект типа напрямую без использования списка T с аргументами std​::​forward<Args>(args)....

Postconditions: *this содержит значение.

Returns: Ссылка на новое содержащееся значение.

Throws: Любое исключение, созданное выбранным конструктором T.

Remarks: Если во время вызова Tконструктора возникает исключение , *this не содержит значения, а предыдущее *val (если оно есть) было уничтожено.

template <class U, class... Args> T& emplace(initializer_list<U> il, Args&&... args);

Effects: Звонки *this = nullopt. Затем инициализирует содержащееся значение, как если бы инициализирует объект типа напрямую без использования списка T с аргументами il, std​::​forward<Args>(args)....

Postconditions: *this содержит значение.

Returns: Ссылка на новое содержащееся значение.

Throws: Любое исключение, созданное выбранным конструктором T.

Remarks: Если во время вызова Tконструктора возникает исключение , *this не содержит значения, а предыдущее *val (если оно есть) было уничтожено. Эта функция не будет участвовать в разрешении перегрузки , если is_­constructible_­v<T, initializer_­list<U>&, Args&&...> не true.

23.6.3.4 Swap [optional.swap]

void swap(optional& rhs) noexcept(see below);

Requires: Lvalues ​​типа T должны быть заменяемыми и is_­move_­constructible_­v<T> есть true.

Effects: См. Таблицу 39.

Таблица 39 - optional​::​swap(optional&) эффекты
*this содержит значение*this не содержит значения
rhs содержит значение звонки swap(*(*this), *rhs) инициализирует содержащееся значение, *this как если бы напрямую без списка инициализирует объект типа T с выражением std​::​move(*rhs), за которым следует rhs.val->T​::​~T(); постусловие - это то, что *this содержит значение и rhs не содержит значения
rhs не содержит значения инициализирует содержащееся значение, rhs как если бы напрямую без списка инициализирует объект типа T с выражением std​::​move(*(*this)), за которым следует val->T​::​~T(); постусловие - это то, *this что не содержит значения и rhs содержит значение нет эффекта

Throws: Любые исключения, вызванные операциями в соответствующей части таблицы 39.

Remarks: Выражение внутри noexcept эквивалентно:

is_nothrow_move_constructible_v<T> && is_nothrow_swappable_v<T>

Если возникает какое-либо исключение, результаты выражений bool(*this) и bool(rhs) остаются неизменными. Если во время вызова функции возникает исключение swap, состояние *val и *rhs.val определяется гарантией безопасности исключений swap для lvalues T. Если во время вызова Tконструктора перемещения возникает исключение , состояние *val и *rhs.val определяется гарантией безопасности исключений Tконструктора перемещения.

23.6.3.5 Observers [optional.observe]

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

Requires: *this содержит значение.

Returns: val.

Throws: Ничего такого.

Remarks: Эти функции должны быть функциями constexpr.

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

Requires: *this содержит значение.

Returns: *val.

Throws: Ничего такого.

Remarks: Эти функции должны быть функциями constexpr.

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

Requires: *this содержит значение.

Effects: Эквивалентен: return std​::​move(*val);

constexpr explicit operator bool() const noexcept;

Returns: true тогда и только тогда, когда *this содержит значение.

Remarks: Эта функция должна быть функцией constexpr.

constexpr bool has_value() const noexcept;

Returns: true тогда и только тогда, когда *this содержит значение.

Remarks: Эта функция должна быть функцией constexpr.

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

Effects: Эквивалентен:

return bool(*this) ? *val : throw bad_optional_access();

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

Effects: Эквивалентен:

return bool(*this) ? std::move(*val) : throw bad_optional_access();

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

Effects: Эквивалентен:

return bool(*this) ? **this : static_cast<T>(std::forward<U>(v));

Remarks: Если is_­copy_­constructible_­v<T> && is_­convertible_­v<U&&, T> есть false, программа сформирована неправильно.

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

Effects: Эквивалентен:

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

Remarks: Если is_­move_­constructible_­v<T> && is_­convertible_­v<U&&, T> есть false, программа сформирована неправильно.

23.6.3.6 Modifiers [optional.mod]

void reset() noexcept;

Effects: Если *this содержит значение, вызывает val->T​::​~T() уничтожение содержащегося значения; в остальном никакого эффекта.

Postconditions: *this не содержит значения.