libcxx中的可选std :: nullopt_t实现

时间:2016-09-30 10:23:16

标签: c++ language-lawyer optional c++17

Clang以这种方式实现std::nullopt_t

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

constexpr nullopt_t nullopt{0}; 

为什么不简单:

struct nullopt_t{};

constexpr nullopt_t nullopt{};

3 个答案:

答案 0 :(得分:5)

根据cppreference

  

std::nullopt_t必须是LiteralType且不能拥有   默认构造函数。它必须有一个constexpr构造函数   一些实现定义的文字类型。

...如果Clang按照您的建议实施nullopt_t,那么它就不能满足要求。现在,如果您想知道为什么存在这些要求(一个不同的问题),答案是:

  

nullopt_t不支持DefaultConstructible,以支持op = {};op = nullopt;作为解除可选对象的语法。

答案 1 :(得分:5)

正如std::nullopt_t所述:

  

备注

     

nullopt_t并非DefaultConstructible同时支持op = {};op = nullopt;作为解除可选对象的语法。

现在用你的实现测试一下:

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 = {};
}

此操作失败,因为对operator=的调用不明确。它可能是尝试调用operator=(nullopt_t),也可能是尝试调用operator=(optional &&),并且没有语言规则来解决这种歧义。

因此,除非语言规则发生变更,或oi = {};不再需要有效,否则nullopt_toptional不能默认构建,nullopt_t 1}}是合乎逻辑的选择。

答案 2 :(得分:1)

其他人解释了为什么struct nullopt_t {};不足。但是至少有两种替代解决方案仍然比目前在libc ++和libstdc ++中使用的解决方案更简单。

(以下是一些测试代码:http://melpon.org/wandbox/permlink/HnFXRjLyqi4s4ikv

以下是妄想症的增加顺序的替代方案:

选项1(据我所知,没有人)

struct nullopt_t { constexpr explicit nullopt_t() {} };
constexpr nullopt_t nullopt{};

选项2(libc ++&lt; experimental / optional&gt;)

struct nullopt_t { constexpr explicit nullopt_t(int) {} };
constexpr nullopt_t nullopt{0};

选项3(libstdc ++&lt; experimental / optional&gt;)

struct nullopt_t {
    enum class secret { tag };
    explicit constexpr nullopt_t(secret) { }
};
constexpr nullopt_t nullopt{nullopt_t::secret::tag};

选项4(libc ++&lt; optional&gt;)

struct nullopt_t {
    struct secret_tag { explicit secret_tag() = default; };
    constexpr explicit nullopt_t(secret_tag, secret_tag) noexcept {}
};
constexpr nullopt_t nullopt{nullopt_t::secret_tag{}, nullopt_t::secret_tag{}};

这些备选方案中的任何一个(即使是备选方案1,据我所知)都足以使赋值o = {}明确无误。我不知道为什么libc ++和libstdc ++都超越了这个解决方案 - 并注意到libc ++甚至创建了一个两参数构造函数!

如果有人知道libc ++增加妄想症的原因,我很乐意听到它;请在下面创建答案和/或发表评论。