我正在尝试理解我观察到的C ++语言行为(我理解了它的前半部分)。
我的设置:2个模板类:A
和C
。 A
可以转换为C
,但不能转换为C
。它们有一些共同的行为,因此我一直在寻找仅使用A
实现某些逻辑,并依赖从C
到A
的转换,使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}},这也不起作用。我认为这是因为现在扣除过程中没有参数。
我是对的吗?
答案 0 :(得分:4)
我认为您的情况由C ++ 11,14.8.2.1 / 4 [temp.deduct.call]描述:
通常,演绎过程会尝试查找模板参数值,这些参数值会使推导的
A
与A
相同(在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),并且注释说明隐式转换仅是考虑到本身不属于扣除过程的类型。