简体   繁体   English

std :: in_place_t和C ++中的朋友17

[英]std::in_place_t and friends in C++17

As of the time of writing, cppreference gives a reasonably simple definition of the std::in_place_t family: 截至编写本文时,cppreference给出了std::in_place_t系列的一个相当简单的定义

struct in_place_t {
    explicit in_place_t() = default;
};
inline constexpr std::in_place_t in_place{};

template <class T>
struct in_place_type_t {
    explicit in_place_type_t() = default;
};

template <class T>
inline constexpr std::in_place_type_t<T> in_place_type{};

template <size_t I> struct in_place_index_t {
    explicit in_place_index_t() = default;
};

template <size_t I>
inline constexpr in_place_index_t<I> in_place_index{};

However, the latest draft of the C++17 standard linked from isocpp.org has a rather more complicated definition (section 20.2.7, page 536): 但是, 从isocpp.org链接的最新C ++ 17标准草案有一个相当复杂的定义(第20.2.7节,第536页):

struct in_place_tag {
    in_place_tag() = delete;
};
using in_place_t = in_place_tag(&)(unspecified );

template <class T>
using in_place_type_t = in_place_tag(&)(unspecified <T>);

template <size_t I>
using in_place_index_t = in_place_tag(&)(unspecified <I>);

in_place_tag in_place(unspecified );

template <class T>
in_place_tag in_place(unspecified <T>);

template <size_t I>
in_place_tag in_place(unspecified <I>);

The first version is simple and easy to understand, but second version is quite opaque to me. 第一个版本简单易懂,但第二个版本对我来说非常不透明。 So, questions: 所以,问题:

  • Which version is correct, post-Issaqua (November 2016)? 哪个版本是正确的,在Issaqua之后(2016年11月)? (Presumably the second, but it's possible that N4606 hasn't yet been updated after the latest meeting and cppreference has.) (可能是第二个,但是在最新的会议和cppreference之后,N4606可能还没有更新。)

  • Clearly this has changed at some point in time; 显然,这在某个时间点发生了变化; does anyone have a link to a paper mentioning the change? 有没有人提到一篇提到变化的论文?

  • Most importantly, can anyone explain how the second version is intended to work? 最重要的是,任何人都可以解释第二个版本的工作原理吗? What would a sample implementation look like? 示例实现是什么样的?

The first version is the right one, currently, and will in all likelihood be the one ending up in C++17. 目前,第一个版本是正确的版本,并且很可能是以C ++ 17结尾的版本。

The second version was an attempt to allow one to write in_place everywhere, with nothing, with a type, or with an index: 第二个版本试图允许一个人在in_place地方写入in_place ,没有任何东西,有类型或索引:

std::optional<int> o(std::in_place, 1);
std::any a(std::in_place<int>, 1);
std::variant<int, int> v(std::in_place<0>, 1);

The only way to make this syntax work is to make in_place an overloaded function, and that also requires making in_place*_t aliases for references to functions. 使这种语法有效的唯一方法是使in_place成为重载函数,并且还需要为函数引用创建in_place*_t别名。 There's no real implementation difference otherwise - the in_place functions aren't meant to be called, they exist only so that a reference to them can be passed around as a tag and match the corresponding _t types. 否则没有真正的实现差异 - in_place函数不是要调用的,它们只是存在,以便对它们的引用可以作为标记传递并匹配相应的_t类型。

Nonetheless it was too clever and caused its own problems (for instance, unlike plain tag types, they don't respond well to being decay 'd, and plain std::in_place , being an overloaded function name, misbehaves with perfect forwarders: std::optional<std::optional<int>> o(std::in_place, std::in_place); doesn't work because the compiler can't resolve the second std::in_place ), so it got backed out in Issaquah, and now you have to write 尽管如此,它太聪明并且引起了它自己的问题(例如,与普通标签类型不同,它们对decay没有很好的反应,而普通的std::in_place是一个重载的函数名称,与完美的转发器行为不端: std::optional<std::optional<int>> o(std::in_place, std::in_place);不起作用,因为编译器无法解析第二个std::in_place ),所以它被取消了Issaquah,现在你必须写

std::optional<int> o(std::in_place, 1);
std::any a(std::in_place_type<int>, 1);
std::variant<int, int> v(std::in_place_index<0>, 1);

A little less pretty, but more sane. 不太漂亮,但更健全。

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

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