条款46:需要类型转换时请为模板定义非成员函数
Define non-member functions inside templates when type conversions are desired.
template<typename T>
class Rational {
public:
Rational(const T& numerator = 0, const T& denominator = 1);
...
};
template<typename T>
const Rational<T> operator*(const Rational<T>& lhs, const Rational<T>& rhs) {
...
}
Rational<int> oneHalf(1, 2);
Rational<int> result = oneHalf * 2; // 无法通过编译
这里编译器并不知道具体该调用哪个函数,因为 operator*
的第一个参数被声明为 Rational<T>
,而传递的实参类型为 Rational<int>
,所以 T 一定是 int。但是第二个实参为 int,编译器在 template 实参推导过程中从不将隐式类型转换函数纳入考虑。而解决的办法是在 template class 内的 friend 声明式中指涉某个特定函数:
template<typename T>
class Rational {
public:
...
friend const Rational operator*(const Rational& lhs, const Rational& rhs);
};
template<typename T>
const Rational<T> operator*(const Rational<T>& lhs, const Rational& rhs) { ... }
因为当对象 oneHalf
被声明为一个 Rational<int>
时,class Rational<int>
于是被具现化出来,而作为过程的一部分,friend 函数 operator*
也就被自动声明出来。
但是这种写法只能通过编译,无法进行连接,因为我们没有提供 friend const Rational operator*
的定义式。所以最优的写法是:
template<typename T> class Rational;
template<typename T>
const Rational<T> doMultiply(const Rational<T>& lhs, const Rational<T>& rhs);
template<typename T>
class Rational {
public:
...
friend
const Rational<T> operator*(const Rational<T>& lhs, const Rational<T>& rhs) {
return doMultiply(lhs, rhs);
}
};
template<typename T>
const Rational<T> doMultiply(const Rational<T>& lhs, const Rational<T>& rhs) {
return Rational<T>(lhs.numerator() * rhs.numerator(), lhs.denominator() * rhs.denominator());
}
Last updated
Was this helpful?