#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。
答案 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_pair
和my_pair2
进行规则更改以允许扣除:
template<typename T> using my_pair3 = std::pair<T, T>;
my_pair3 mp3 = {1, 2};
这里涉及的复杂性与继承的构造函数情况大致相同。 Faisal Vali(类模板参数演绎的其他设计者之一)有一个具体的计划,如何使这些案例工作,但C ++委员会尚未讨论这个扩展。