这对于那里的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);
}
我有一个类“错误”,我想要进行加法操作。当我尝试:
X a, b;
Mistake<int> foo = a + b;
我收到编译错误;编译器似乎无法意识到模板操作符+必须实例化。
另一方面,如果我之前添加以下代码:
Mistake<int> operator+(const Mistake<int>& a, const Mistake<int>& b)
{
return Mistake<int>(a.x + b.x);
}
然后一切都很顺利。任何人都有任何线索的原因?我怀疑编译器无法弄清楚要实例化什么,因为从类X到类Mistake需要类型转换,但我不知道如何解决这个问题,而不是根本不使用模板。
顺便说一句,将类中的运算符定义为朋友也不起作用。
谢谢!
答案 0 :(得分:10)
虽然其他人已经为您的问题提出了可行的解决方案,但我想指出发生了什么,以及为什么您的期望无法满足。
此处的问题是,在执行类型扣除时,不会考虑用户定义的转化。当编译器出现时使用以下表达式:
a + b
a
和b
的类型X
以及operator +
的以下签名:
template <class T>
Mistake<T> operator+(const Mistake<T>& a, const Mistake<T>& b)
编译器要做的第一件事是尝试推导T
,以便运算符的参数类型匹配 exaclty 参数的类型。如果无法做到这一点,编译器会立即放弃,而不考虑可能的转换构造函数,并专注于其他候选函数(或函数模板)。
考虑到上述情况,很明显无法让Mistake<T>
成为 exaclty X
,无论你选择T
({{1} }}不是Mistake<int>
,X
不是Mistake<X>
,依此类推)。因此,替换失败并且编译器不知道如何解析调用,因为周围没有其他候选者。
另一方面,如果你有这个:
X
不涉及类型推导,因为上面不是函数模板。因此,编译器将在尝试解析调用时将用户定义的转换考虑在内,并且由于Mistake<int> operator+(const Mistake<int>& a, const Mistake<int>& b)
具有接受Mistake<int>
的构造函数,因此{{1}被认为是一个可行的候选者,它被选中了。
答案 1 :(得分:3)
我认为没有办法。你能做到的最纯粹的是
Mistake<int> foo = static_cast<Mistake<int>>(a) + static_cast<Mistake<int>>(b);
或者如果你使用一个匹配不对称操作数类型的额外重载来推动它:
template <class T, class U>
Mistake<T> operator+(const Mistake<T>& a, U const& b) {
return a + static_cast<Mistake<T>>(b);
}
// and later:
foo = Mistake<int>(a) + b;
完整的现场演示:http://ideone.com/ki14GO
#include <iostream>
class X { };
template <class T>
class Mistake {
public:
T x;
Mistake(const T& k) : x(k) { }
Mistake(const X&) : x(1) { }
void print() { std::cout << x << std::endl; }
};
template <class T>
Mistake<T> operator+(const Mistake<T>& a, const Mistake<T>& b) {
return Mistake<T>(a.x + b.x);
}
template <class T, class U>
Mistake<T> operator+(const Mistake<T>& a, U const& b) {
return a + static_cast<Mistake<T>>(b);
}
template <class T, class U>
Mistake<T> operator+(const U& a, Mistake<T> const& b) {
return static_cast<Mistake<T>>(a) + b;
}
int main()
{
X a, b;
Mistake<int> foo = static_cast<Mistake<int>>(a) + static_cast<Mistake<int>>(b);
foo = Mistake<int>(a) + b;
foo = a + Mistake<int>(b);
}
答案 2 :(得分:1)
我认为编译器在推断a + b
的类型时存在问题。
您可以定义:
X operator+(const X & a, const X & b) {
return a /* ??? or something else */;
}
如果您有任何方法可以告诉a + b
X
的答案是什么。