本条款首先以一个看似无害的改动扩充条款24的讨论;本条款将Rational和operator*模板化了:
template <typename T>
class Rational {
public:
Rational(const T& numerator = 0, const T& denominator = 1);
const T numerator() const;
const T denominator() const;
...
};
template <typename T>
const Rational<T> operator* (const Rational<T>& lhs, const Rational<T>& rhs)
{...}
我们希望以下代码顺利通过编译,operator*
支持交换律:
Rational oneHalf(1, 2);
Rational result = oneHalf * 2; // error!
编译器无法推导出T是什么类型, operator*
无法被正确实例化。oneHalf的类型是 Rational<int>
,所以T一定是int,而 2
无法推导出T的类型,因为在template实参推导的过程中从不将隐式类型转换函数纳入考虑。
template class内的friend声明可以指定某个特定函数,那么 operator*
可以是 Rational<T>
的friend函数。类模板并不依赖模板实参推导,因此,令 Rational<T>
声明 operator*
为friend函数可以简化整个问题:
template <typename T>
class Rational {
public:
...
friend const Rational operator*(const Rational& lhs,
const Rational& rhs) {
return Rational(lhs.numerator() * rhs.numerator(),
lhs.denominator() * rhs.denominator());
}
};
现在,我们所期望的正常运行起来。
请记住
- 当我们编写一个class template,而它所提供的与模板相关的函数支持所有参数的隐式类型转换时,请将那些函数定义为class template的内部friend函数。