C++变体:为什么转换构造函数需要sizeof ...(Types)非零

Kil*_*ian 7 c++ c++17

这个问题是关于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表示转换构造函数不应参与重载决策,除非:

sizeof ...(类型)非零

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

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

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

P.W*_*P.W 6

作为本文的一部分,添加了"sizeof ...(Types)非零"这一条款[variant.ctor]:对类模板参数推导集成到标准库中的一些改进也允许variant支持.

相关摘录:

启用变体支持

以下代码无法编译

variant<int, double> v1(3);
variant v2 = v1;  // Ill-formed! <--THIS
Run Code Online (Sandbox Code Playgroud)

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

措辞 (强调增加)
改变§23.7.3.1p16[variant.ctor]如下:
备注:除非sizeof...(Types)是非零,否则此函数不应参与重载决议,除非is_same_v<decay_t<T>, variant>false,除非decay_t<T>是,除非是,除非表达式为FUN ,否则不是专业化in_place_type_t或专业化(std :: forward(t))(FUN是上面提到的虚函数集)形成良好.in_place_index_tis_constructible_v<Tj, T>true

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