std :: in_place_t和C 的朋友17

std::in_place_t and friends in C++17

本文关键字:朋友 in place std      更新时间:2023-10-16

在写作时,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{};

然而,从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>);

第一个版本简单易懂,但是第二版对我来说是非常不透明的。所以,问题:

  • 哪个版本是正确的,issaqua(2016年11月)?(大概是第二个

  • 显然,这在某个时间点发生了变化。有人有提及更改的论文的链接吗?

  • 最重要的是,谁能解释第二版本打算如何工作?示例实现是什么样的?

第一个版本是正确的,目前是正确的,很可能是C 17中最终的版本。

第二个版本是试图允许一个人在任何地方写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);

使此语法工作的唯一方法是使in_place成为一个超载的函数,这也需要使in_place*_t别名以引用函数。否则就没有实际的实现差异 - in_place函数并不是要调用,它们仅存在,以便可以将其引用作为标签传递并匹配相应的_t类型。

尽管如此,它太聪明了,并且引起了自己的问题(例如,与普通标签类型不同,它们对decay'D的反应不佳,而普通的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);

少一些漂亮,但更理智。