类模板参数推导因派生类而失败

时间:2017-10-23 16:25:43

标签: c++ templates g++ c++17 template-deduction

#include <utility>

template<class T1, class T2>
struct mypair : std::pair<T1, T2>
{ using std::pair<T1, T2>::pair; };

int main()
{
    (void)std::pair(2, 3); // It works
    (void)mypair(2, 3);    // It doesn't work
}

以上是否形成良好?

如果继承构造函数,是否可以在第二种情况下推导出类模板参数? std::pair的构造函数是否参与了mypair的隐式演绎指南的创建?

我的编译器是g ++ 7.2.0。

2 个答案:

答案 0 :(得分:4)

我认为这是一个gcc bug(或者至少是一个次要的核心语言措辞缺陷)。

根据{{​​3}},

继承的构造函数执行计为构造函数:

  

同样,在查找派生类([class.qual])的构造函数或者形成时,由 using-declaration 引入的构造函数被视为派生类的构造函数。一组重载候选者([over.match.ctor],[over.match.copy],[over.match.list])

该条件列表在技术上不包括[over.match.class.deduct],但暗示基类构造函数是派生类的构造函数。 [namespace.udecl]/16中的规则是考虑:

  

如果定义了C,对于{{1>}的每个构造函数,则具有以下属性的函数模板[...]

我们正在查找派生类的构造函数,而不是在任何列出的情况下。但是这个例子应该在概念上起作用:

C

答案 1 :(得分:4)

简短的故事:标准中没有规则说明这是如何运作的,也没有任何规则说明它不起作用。所以GCC和Clang保守地拒绝而不是发明(非标准)规则。

长篇故事: mypair&#39; pair基类是一种依赖类型,因此查找其构造函数无法成功。对于mytype<T1, T2>的每个特化pair<T1, T2>的相应构造函数是mytype的构造函数,但这不是可以有意义地应用于模板优先级的规则一般的实例化。

原则上,可能存在一条规则,即在这种情况下你会看到主要pair模板的构造函数(就像我们在为类模板查找mypair本身的构造函数时所做的那样参数推论),但目前标准中实际上并没有这样的规则。但是,当基类变得更复杂时,这样的规则很快就会失败:

template<typename T> struct my_pair2 : std::pair<T, T> {
  using pair::pair;
};

应该在理论上注入哪些构造函数?在这种情况下,我认为这种查找不可能有效:

template<typename T> struct my_pair3 : arbitrary_metafunction<T>::type {
  using arbitrary_metafunction<T>::type::type;
};

如果/当我们获得别名模板的类模板参数扣除规则时,我们可以通过您的my_pairmy_pair2进行规则更改以允许扣除:

template<typename T> using my_pair3 = std::pair<T, T>;
my_pair3 mp3 = {1, 2};

这里涉及的复杂性与继承的构造函数情况大致相同。 Faisal Vali(类模板参数演绎的其他设计者之一)有一个具体的计划,如何使这些案例工作,但C ++委员会尚未讨论这个扩展。