我试图理解我观察到的 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
}
这实际上是我在搜索SO和网络后认为我理解的前半部分。根据我收集的信息,模板参数必须完全匹配,然后才能尝试转换,在这种情况下,如果不考虑可能的转换就无法推断,因此无法推断。C
如果操作员成为非模板朋友(但我不喜欢它),则可以避免这种情况。
我尝试的下一件事是使用继承:
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
(第一种情况)?
编辑
正如我尝试过的评论中 KerrekSB 所建议的那样:
template <class T>
bool operator<(const C<T> &, const typename std::common_type<C<T>>::type &) {return true;}
我的第一个案例(转换,而不是继承)
在这种情况下:
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
. 我认为这是因为现在推演过程中不涉及任何参数。
我对吗?