1

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

我的设置:2 个模板类:AC. 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. 我认为这是因为现在推演过程中不涉及任何参数。

我对吗?

4

1 回答 1

4

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

一般来说,推导过程试图找到模板参数值,使推导的值AA(在A如上所述转换类型之后)相同。但是,有三种情况允许不同:

— ...

— 如果P是一个类并且P具有simple-template-id的形式,那么转换后的A可以是 deduced 的派生类A。同样,如果P是一个指向simple-template-id形式的类的指针,则转换后的A可以是指向 deduced 指向的派生类的指针A

[注意:如 14.8.1 中所述,如果参数不包含参与模板参数推导的模板参数,则会对函数参数执行隐式转换以将其转换为相应函数参数的类型。除了前面列表中描述的转换之外,还允许进行此类转换。——尾注]

列出的子句说派生类型是可以的(注意这C<T>是一个simple-template-id,由 14.2/1 ),并且注释解释说隐式转换只考虑那些本身不是推导过程的一部分的类型。

于 2014-04-03T21:03:00.307 回答