This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of NAD status.

3562. Superseding nullopt_t's requirement to not be DefaultConstructible

Section: 22.5.4 [optional.nullopt] Status: NAD Submitter: David Friberg Opened: 2021-06-04 Last modified: 2021-06-14

Priority: Not Prioritized

View all other issues in [optional.nullopt].

View all issues with NAD status.

Discussion:

22.5.4 [optional.nullopt] p2 requires that nullopt_t shall not have a default constructor ([…] or an initializer-list constructor, and shall not be an aggregate). However, after the final resolution of LWG issue 2510 and CWG 1518 it seems as if the following synopsis would suffice:

struct nullopt_t { explicit nullopt_t() = default; };

Which would also be consistent with other tag types.

22.5.4 [optional.nullopt] p2 in its current form was written prior to the final resolution of LWG issue 2510 and CWG 1518, and is arguably based on using an earlier proposed approach for tag types which was later superseded.

Details:

P0032R3 was part of introducing optional and contained a discussion around the nullopt_t type, tag types in general, and the DefaultConstructible requirement. Particularly, from section 'Not assignable from {}':

To re-enforce this design, there is an pending issue 2510-Tag types should not be DefaultConstructible Core issue 2510.

At the time of P0032R3, the resolution of LWG issue 2510 was indeed for all tag types to not be DefaultConstructible, but this resolution was later superseded as part of the resolution of CWG issue CWG 1518, which in turn reverted parts of the resolution of CWG issue CWG 1630 (which "went too far in allowing use of explicit constructors for default initialization").

The final resolution for CWG 1518 (P0398R0) lead to the requirement for aggregate classes to not have any explicit [user-declared] constructors, and LWG 2510 was resolved accordingly by making all tag types have explicit user-declared (constexpr) default constructors.

However, the spec of nullopt_t never changed after these events or as part of updating other tag types, and it is still explicitly required to not be DefaultConstructible (nor have a initialization-list constructor) and to not be an aggregate, whereas the implementation of it is otherwise unspecified.

We may note that we still see some compiler variance on the topic of CWG issues 1518 & 1630, see this godbolt link.

[2021-06-14 Reflector poll: Current wording prevents an implicit conversion sequence from {}. Status changed: New → NAD.]

Proposed resolution:

This wording is relative to N4885.

  1. Modify 22.5.2 [optional.syn], header <optional> synopsis, as indicated:

    […]
    
    // 22.5.4 [optional.nullopt], no-value state indicator
    struct nullopt_t{see below explicit nullopt_t() = default; };
    inline constexpr nullopt_t nullopt{}(unspecified);
    
    […]
    
  2. Modify 22.5.4 [optional.nullopt] as indicated:

    struct nullopt_t{see below explicit nullopt_t() = default; };
    inline constexpr nullopt_t nullopt{}(unspecified);
    

    -1- The struct nullopt_t is an empty class type used as a unique type to indicate the state of not containing a value for optional objects. In particular, optional<T> has a constructor with nullopt_t as a single argument; this indicates that an optional object not containing a value shall be constructed.

    -2- Type nullopt_t shall not have a default constructor or an initializer-list constructor, and shall not be an aggregate.