需要类型转换时请为模板定义非成员函数
在条款24中,
class Rational
{
public:
const int numerator() const {return n;}
const int denominator() const {return d;}
private:
int n,d;
};
const Rational operator*(const Rational& lhs,const Rational& rhs)//非成员函数,
{
return Rational(lhs.numerator() * rhs.numerator(), lhs.denominator() * rhs.denominator());
}
Rational oneFourth(1,4);
Rational result;
result = oneFourth * 2;
result = 2 * oneFourth;
//只有当参数被列于参数列内,这个参数才是隐式类型转换的合格参与者
但如若考虑template
template<typename T>
class Rational
{
public:
const T numerator() const {return n;}
const T denominator() const {return d;}
private:
T n,d;
};
template<typename T>
const Rational<T> operator*(const Rational<T>& lhs,const Rational<T>& rhs)//非成员函数,
{...}
Rational<int> oneFourth(1,4);
Rational<int> result = oneFourth * 2;//wrong????
发生错误的原因在于:
在条款24中的代码中,编译器知道调用的函数是接受两个Rational参数的operator*。但是在后面的模板代码中,第一个参数是Rational< int >(oneFourth),第二个是int(2),编译器只知道可以具现化一个名为operator *并接受两个Rational< T >参数的函数,此时,即使通过构造函数可以实现内置类型到对应的模板类的隐式转换(例如,int->Rational< int >),然而,template实参推导过程中并不考虑采纳“通过构造函数发生的”隐式类型转换。因此编译器不知道应该调用哪个函数。
解决方法:令Rational< T >class声明适当的operator* 为其friend函数:
template<typename T>
class Rational
{
friend const Rational operator*(const Rational& lhs,const Rational& rhs)
{
return Rational(lhs.numerator() * rhs.numerator(), lhs.denominator() * rhs.denominator());
}
};
Rational<int> oneFourth(1,4);
Rational<int> result = oneFourth * 2;//可以编译通过。
说明:在一个class template内,template名称可被用来作为“template和其参数”的简略表达方式,所以Rational< T >可以写为Rational。因为当oneFourth 被声明为一个Rational< int > ,class Rational< int >被具现化,而作为过程中的一部分,friend函数operator*(接受Rational< int >参数)也被声明出来,身为一个函数而非函数模板,因此编译器可在调用它时使用隐式转换函数。
许多编译器实质上会强迫你把所有template定义式放进头文件中。