简体   繁体   English

libcxx中的可选std :: nullopt_t实现

[英]optional std::nullopt_t implementation in libcxx

Clang implements std::nullopt_t this way: Clang std::nullopt_t这种方式实现std::nullopt_t

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

constexpr nullopt_t nullopt{0}; 

Why not simply: 为什么不简单:

struct nullopt_t{};

constexpr nullopt_t nullopt{};

?

According to cppreference : 根据cppreference

std::nullopt_t must be a LiteralType and cannot have a default constructor. std::nullopt_t必须是LiteralType,并且不能有默认构造函数。 It must have a constexpr constructor that takes some implementation-defined literal type. 它必须有一个constexpr构造函数,它采用一些实现定义的文字类型。

... so if Clang implemented nullopt_t as you suggested, it wouldn't meet the requirements. ...所以如果Clang按照你的建议实现了nullopt_t ,那就不符合要求了。 Now, if you are wondering why those requirements exist (a different question), the answer is: 现在,如果您想知道为什么存在这些要求(一个不同的问题),答案是:

nullopt_t is not DefaultConstructible to support both op = {}; nullopt_t不是DefaultConstructible以支持op = {}; and op = nullopt; op = nullopt; as the syntax for disengaging an optional object. 作为脱离可选对象的语法。

As mentioned on std::nullopt_t : std :: nullopt_t中所述

Notes 笔记

nullopt_t is not DefaultConstructible to support both op = {}; nullopt_t不是DefaultConstructible以支持op = {}; and op = nullopt; 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. 这失败了,因为对operator=的调用是不明确的。 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. 它可能是尝试调用operator=(nullopt_t) ,或者它可能是尝试调用operator=(optional &&) ,并且没有语言规则来解决这种歧义。

Therefore, unless there's a change to the language rules, or oi = {}; 因此,除非语言规则发生变化,否则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. 不再需要有效, nullopt_t或者optional不需要是default-constructible,而nullopt_t是它的逻辑选择。

Others have explained why struct nullopt_t {}; 其他人解释了为什么struct nullopt_t {}; is insufficient. 不够。 But there are at least two alternative solutions that are still simpler than the ones currently ensconced in libc++ and libstdc++. 但是至少有两种替代解决方案仍然比目前在libc ++和libstdc ++中实现的解决方案更简单。

(Here's some test code: http://melpon.org/wandbox/permlink/HnFXRjLyqi4s4ikv ) (这是一些测试代码: http//melpon.org/wandbox/permlink/HnFXRjLyqi4s4ikv

Here are the alternatives, in increasing order of paranoia: 以下是偏执狂递增顺序的替代方案:

Option 1 (nobody as far as I know) 选项1(据我所知,没有人)

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

Option 2 (libc++ <experimental/optional>) 选项2(libc ++ <experimental / optional>)

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

Option 3 (libstdc++ <experimental/optional>) 选项3(libstdc ++ <experimental / optional>)

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

Option 4 (libc++ <optional>) 选项4(libc ++ <optional>)

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

Any one of these alternatives (even Option 1, as far as I know) would suffice to make the assignment o = {} unambiguous. 这些备选方案中的任何一个(即使是备选方案1,据我所知)都足以使赋值o = {}明确无误。 I don't know why both libc++ and libstdc++ go beyond that solution — and notice that libc++ goes so far as to create a two-argument constructor! 我不知道为什么libc ++和libstdc ++都超越了这个解决方案 - 并注意到libc ++甚至创建了一个双参数构造函数!

If anyone knows the reason for libc++'s increased paranoia, I'd love to hear it; 如果有人知道libc ++增加妄想症的原因,我很乐意听到它; please create an answer and/or leave a comment below. 请在下面创建答案和/或发表评论。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM