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

时间:2019-02-04 20:32:36

标签: 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 ...(Types)不为零

(...和我暂时不在乎的其他一些要求)。

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

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

1 个答案:

答案 0 :(得分:6)

条款“ sizeof ...(Types)为非零” 已添加到 [variant.ctor] 中,作为论文的一部分:Some improvements to class template argument deduction integration into the standard library也允许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起)。请参见{{3} }。