模板化操作符实例化和类型转换

Fer*_*ndo 13 c++ templates overloading operator-keyword

这对于那里的C++大师来说.

请考虑以下代码:

class X { };

template <class T>
class Mistake {
public:
  T x;

  Mistake(const T& k) : x(k) { }
  Mistake(const X&) : x(1) { }

  void print() { cout << x << endl; }
};

template <class T>
Mistake<T> operator+(const Mistake<T>& a, const Mistake<T>& b)
{
  return Mistake<T>(a.x + b.x);
}
Run Code Online (Sandbox Code Playgroud)

我有一个类"错误",我想要进行加法操作.当我尝试:

X a, b;
Mistake<int> foo = a + b;
Run Code Online (Sandbox Code Playgroud)

我收到编译错误; 编译器似乎无法意识到必须实例化模板运算符+.

另一方面,如果我之前添加以下代码:

Mistake<int> operator+(const Mistake<int>& a, const Mistake<int>& b)
{
  return Mistake<int>(a.x + b.x);
}
Run Code Online (Sandbox Code Playgroud)

那一切都很好.任何人都有任何线索的原因?我怀疑编译器无法弄清楚要实例化什么,因为从类X到类Mistake需要类型转换,但我不知道如何解决这个问题,而不是根本不使用模板.

顺便说一句,将类中的运算符定义为朋友也不起作用.

谢谢!

And*_*owl 10

虽然其他人已经提出了解决问题的可能方案,但我想指出发生了什么,以及为什么无法满足您的期望.

这里的问题是在执行类型推导时不考虑用户定义的转换.当编译器显示此表达式时:

a + b
Run Code Online (Sandbox Code Playgroud)

如果双方ab有型的X,而对于以下签名operator +:

template <class T>
Mistake<T> operator+(const Mistake<T>& a, const Mistake<T>& b)
Run Code Online (Sandbox Code Playgroud)

编译器会做的第一件事就是尝试和推断T,这样的类型的操作者匹配的参数exaclty类型的参数.如果这是不可能的,编译器会立即放弃,而不考虑可能的转换构造函数,并专注于其他候选函数(或函数模板).

考虑到上面的情况,很明显,无论你选择什么(不是,不是等等),都没有办法Mistake<T>变得无礼 .因此,替换失败,编译器不知道如何解析调用,因为周围没有其他候选者.XTMistake<int>XMistake<X>X

另一方面,当你有这个:

Mistake<int> operator+(const Mistake<int>& a, const Mistake<int>& b)
Run Code Online (Sandbox Code Playgroud)

没有涉及类型推导,因为上面不是函数模板.因此,编译器在尝试解析调用时考虑用户定义的转换,并且由于Mistake<int>有一个接受一个的构造函数,X上面operator +被认为是一个可行的候选者,并且它被选中.