std::nullopt_t 构造原理

std::nullopt_t constructor rationale

this page

所述

std::nullopt_t must be a LiteralType and cannot have a default constructor. It must have a constexpr constructor that takes some implementation-defined literal type. ... Notes nullopt_t is not DefaultConstructible to support both op = {}; and op = nullopt; as the syntax for disengaging an optional object.

...并且,一个可能的实现是

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

其实看完后我不太明白背后的道理。

(1) 为什么要nullopt_t而不是DefaultConstructible?我不太明白“...支持两者...”部分。

(2) 为什么可能的构造函数采用 int,而 boost::none_t 采用空类型 boost::none_t::init_tag?这两种实现方式有何不同?

Why make nullopt_t not DefaultConstructible?

cppreference 需要一个小的修复。 "not DefaultConstructible" 不是预期语义的正确描述。1

无论如何,目的是给定 operator=(optional&&)operator=(nullopt_t)opt = {} 将明确地转到第一个,而不是引起歧义,这是通过使得无法从 {} 构建 nullopt_t。请注意 "assign a value" operator= 是一个模板,因此对于 = {} 也是不可行的。

Why would a possible ctor takes an int, while boost::none_t takes an empty type boost::none_t::init_tag? How do these two implementations differ?

标准未指定如何构造 nullopt_t。 (你应该使用 nullopt。)所以通常你只是添加一个构造函数接受 something 并忽略它。 something 究竟是什么取决于实施者。


1下面的病态实现满足了当前工作稿中的所有要求,不是DefaultConstructible,但还是打破了opt = {}

struct nullopt_t {
    constexpr nullopt_t(const nullopt_t&) = default;
};

constexpr nullopt_t nullopt(nullopt_t{});