vladon vladon - 12 days ago 6
C++ Question

optional std::nullopt_t implementation in libcxx

Clang implements

std::nullopt_t
this way:

struct nullopt_t
{
explicit constexpr nullopt_t(int) noexcept {}
};

constexpr nullopt_t nullopt{0};


Why not simply:

struct nullopt_t{};

constexpr nullopt_t nullopt{};


?

hvd hvd
Answer

As mentioned on std::nullopt_t:

Notes

nullopt_t is not DefaultConstructible to support both op = {}; and op = nullopt; as the syntax for disengaging an optional object.

Now test this with your implementation:

struct nullopt_t { };
template <typename T>
struct optional {
  optional &operator=(nullopt_t);
  optional &operator=(const optional &);
  optional &operator=(optional &&);
  template <typename U>
  optional &operator=(U &&);
};
int main() {
  optional<int> oi;
  oi = {};
}

This fails, because the call to operator= is ambiguous. It could be an attempt to call operator=(nullopt_t), or it could be an attempt to call operator=(optional &&), and there is no language rule to resolve this ambiguity.

Therefore, unless there's a change to the language rules, or oi = {}; no longer needs to be valid, either nullopt_t or optional needs to not be default-constructible, and nullopt_t is the logical choice for that.