Item 46: 需要类型转换时请为模板定义非成员函数

我们在Item 24提到过用将Rational的operator*声明为non-member,从而使2*oneHalf得以成功调用该函数。这是在没有template的情况下。Rational和operator*被模板化后会怎样呢?

template<typename T>
clas Rational{
  public:
    Rational( const T& numerator=0, const T& denumerator=1 );
    const T numerator() const;
    const T denumerator() const;
    ...
};
template<typename T>
const Rational<T> operator* ( const Rational<T>& lhs, const Rational<T>& rhs ){
  ...
}

加上模板后,我们又不能成功调用2*oneHalf了。为什么呢?编译器是根据调用operator*的参数类型的推导来具现化operator*的。template在实参推导过程中从不将隐式类型转换函数纳入考虑。这样的转换在函数调用过程中的确被使用,但在能够调用一个函数之前,首先必须知道那个函数存在。编译器找不到哪个模板可以生成operator*( Rational&, int& )函数,在具现化之前又不考虑int到Rational的隐式转换,因此最终编译器找不到适当的函数来调用2*oneHalf。
解决这个问题的关键在于:template class内的friend声明式可以指涉某个特定函数。class template并不倚赖template实参推导(实参推导只发生在function template上),所以编译器总是能够在class Rational具现化时得知T。因此令Rational class声明适当的operator*为其friend函数:

template<typename T>
class Rational{
  public:
    ...
      //当某一Rational<T>被具现化出来后,对应于Rational<T>的operator*版本
      //也被具现化出来,它明确说明它的第一个参数是Rational<T>
      //第二个参数也是Rational<T>,这时候隐式转换就能发挥作用了
      friend const Rational operator*( const Rational& lhs,
                    const Rational& rhs );
};
//该函数并非上述声明式operator*函数的定义
template<typename T>
const Rational<T> operator*( const Rational<T>& lhs, const Rational<T> rhs ){
  ...
}

friend的作用是为了让在class类内声明的函数变成non-member函数,能完成这一目标的不止friend一个,static也可以做到。
现在,编译器知道该为2*oneHalf调用哪个函数了,可是,我们还没有提供定义式!(注意:下面的模板函数跟上面的friend函数没有半毛钱关系。)我们只是声明了这个函数,去哪里定义它呢?看来唯一可以定义该函数的地方就在class定义体内了。而定义于class内部的函数都暗自成为inline函数,自然的,像operator*这样的函数成为inline函数问题也不大,但是如果函数本体很长呢?让它什么事情都不做,只调用定义于class外部的辅助函数:

template<typename T> class Rational;    //声明Rational template
template<typename T> //声明helper template
const Rational<T> doMultiply( const Rational<T>& lhs,
                const Rational<T>& rhs ){ ... }
template<typename T>
class Rational{
  public:
    ...
      friend Rational<T> operator*( const Rational<T>& lhs, 
                    const Rational<T>& rhs ){
    return doMultiply( lhs, rhs ); }
    ...
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值