C++变体:为什么转换构造函数需要大小.(类型)为非零

C++ Variant: Why does Converting constructor require sizeof...(Types) to be nonzero

本文关键字:类型 变体 为什么 转换 构造函数 C++      更新时间:2023-10-16

这个问题是关于:template<class...Types> class variant

根据 variant.variant/3,在没有模板参数的情况下实例化variant的程序格式不正确。

到目前为止,如此清晰。现在我有一个关于转换构造函数的问题(template<class T> constexpr variant(T&& t) noexcept(see below)):

variant.variant/variant.ctor-16.1 表示转换构造函数不得参与重载解析,除非:

大小...(类型)为非零

(...以及其他一些我现在不关心的要求)。

我的问题是,当没有模板参数的variant已经使我的程序格式不正确时,为什么还要关心我的转换构造函数是否参与重载解析?

看看 MSVC 和 libstdc++ -variant的实现,他们实际上对转换构造函数的声明有enable_if_t<sizeof...(_Types) != 0>。为什么?

子句"sizeof...(类型)为非零">作为论文的一部分添加到[variant.ctor]:对类模板参数推导的一些改进集成到标准库中,以允许variant支持。

相关摘录:

启用变体支持

以下代码编译失败

variant<int, double> v1(3);
variant v2 = v1;  // Ill-formed! <--THIS

由于这种自然代码很有用,并且它的失败令人困惑,我们建议支持它。事实上,在采用 p0510r0 禁止variant<>之前,上面的代码按预期工作,因为variant<>发生在过载集中的一些演绎指南中。由于不清楚在采用 p0510r0 时是否考虑了构造函数模板参数推导,因此我们想考虑允许variant<>在这种情况下不产生硬错误。

措辞(着重号另加)
更改§23.7.3.1p16[variant.ctor]如下:
备注:此函数不应参与重载解析,除非sizeof...(Types)为非零,除非is_same_v<decay_t<T>, variant>false,除非decay_t<T>既不是in_place_type_t的特化也不是in_place_index_t的特化,除非is_constructible_v<Tj, T>true的,除非表达式 FUN(std::forward(t))(FUN是上述虚函数的集合)格式良好。

因此,std::variant v2 = v1;未考虑添加子句的编译器版本中失败(如GCC 7.1。请参阅DEMO),但在更高版本(从 GCC 7.2 开始)上成功。请参阅演示)。