模板推导:为什么它与继承一起工作(当转换失败时)?

时间:2014-04-03 20:43:58

标签: c++ inheritance template-deduction

我正在尝试理解我观察到的C ++语言行为(我理解了它的前半部分)。

我的设置:2个模板类:ACA可以转换为C,但不能转换为C。它们有一些共同的行为,因此我一直在寻找仅使用A实现某些逻辑,并依赖从CA的转换,使C的行为与template <class T> class A { }; template <class T> class C { public: C() = default; C(const A<T>&) {}; }; template <class T> bool operator<(const C<T> &, const C<T> &) {return true;} int main() { A<int> a1, a2; C<int> c1, c2; c1 = a1; // OK, no-brainer c1 < c2; // OK, no-brainer c1 < a1; // template deduction failure a1 < c1; // template deduction failure a1 < a2; // template deduction failure }
这些示例使用了运算符重载,但我认为讨论与函数或方法相同。

我首先尝试使用转换构造函数:

C

这实际上是我认为在搜索SO和网络后我理解的上半部分。根据我收集的内容,模板参数必须在尝试转换之前完全匹配,在这种情况下,不能在不考虑可能的转换的情况下推断它,因此无法进行推断。如果操作员在template <class T> class C { }; template <class T> class A : public C<T> { }; template <class T> bool operator<(const C<T> &, const C<T> &) {return true;} int main() { A<int> a1, a2; C<int> c1, c2; c1 = a1; // Ok, slicing c1 < c2; // Ok, no-brainer c1 < a1; // Ok, but why? a1 < c1; // Ok, but why? a1 < a2; // Ok, but why? } 中成为非模板朋友(但我不喜欢),则可以规避这一点。

我尝试的下一件事是使用继承:

A

为此,我没有在网上找到解释(也许我不知道如何搜索)。

我的问题是,当C可转换为C时,为什么可以推导出模板,因为A的基类(第二种情况),但C时无法推断出}只能转换为template <class T> bool operator<(const C<T> &, const typename std::common_type<C<T>>::type &) {return true;} (第一种情况)?


修改

正如KerrekSB在评论中所建议的那样:

c1 < c2; // OK
c1 < a1; // OK, a1 is converted
a1 < c1; // template deduction failure
a1 < a2; // template deduction failure

我的第一个案例(转换,而不是继承)

在这种情况下:

c1 < a1

使用他的回答我认为template <class T> bool operator<(const typename std::common_type<C<T>>::type &, const typename std::common_type<C<T>>::type &) {return true;} 有效,因为第二个参数不是推论过程的一部分,因此第二个参数会考虑隐式转换。

我也尝试过:

c1 < c2

即使使用{{1}},这也不起作用。我认为这是因为现在扣除过程中没有参数。

我是对的吗?

1 个答案:

答案 0 :(得分:4)

我认为您的情况由C ++ 11,14.8.2.1 / 4 [temp.deduct.call]描述:

  

通常,演绎过程会尝试查找模板参数值,这些参数值会使推导的AA相同(在A类型转换后如上所述)。但是,有三种情况可以产生差异:

     

- ...

     

- 如果P是一个类而P的格式为 simple-template-id ,则转换后的A可以是推导出A。同样,如果P是指向 simple-template-id 形式的类的指针,则转换后的A可以是指向推导出的派生类的指针。 A

     

[注意:如14.8.1中所述,如果参数不包含参与的模板参数,将对函数参数执行隐式转换,以将其转换为相应函数参数的类型在模板参数演绎中。除了前面列表中描述的转换之外,还允许这样的转换。 - 结束记录]

列出的子句说派生类型是正常的(注意C<T> simple-template-id ,按14.2 / 1),并且注释说明隐式转换仅是考虑到本身不属于扣除过程的类型。