Effective C++ 46条 需要类型转换时请为模板定义非成员函数

背景:承接条款24条(请先去了解),那么,之于template实现版本呢?

template<tyname 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)
{...}

我们希望以下代码编译通过:

Rational<int> oneHalf(1, 2);
Rational<int> result = oneHalf * 2;//错误无法通过编译

上述的错误产生在实参推到环节上,先对oneHalf进行推导,operator*的第一个参数被声明为Rational<T>,而传递的第一个参数是Rational<int>,所以T一定是int;但是第二个参数是2,由于template实参推导不会考虑隐式类型转换函数,所以2无法转换成Rational<int>进而推导出T为int。隐式转换存在与函数调用的过程中,但是在能够调用一个函数之前,首先必须知道该函数的存在,而为了知道它,必须先为相关的函数模板推导出参数类型,然后才能将函数具现化。然而,模板实参推导过程中并不考虑采纳“通过构造函数而发生的”隐式类型转换。


应对这种问题:考虑到class Rational<T>具现化时,我们就能得知T。这样我们可在累内声明适当的operator*为其friend函数,那么可以简化整个问题:

template<tyname T>
class Rational
{
public:
    ...
    friend const Rational operator *(const Rational &lhs, const Rational & rhs);
};

//这里是friend函数的实现
template<typename T>
const Rational<T> operator*(const Rational<T> & lhs, const Rational<T> & rhs)
{...}

这样2就可以调用它的隐式转换函数(Rational的non-explicit构造函数),这样就可以编译通过了,但是连接是失败的。

原因非常简单,因为声明在Rational内的operator*没有被定义出来。于是我们这样既可:

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());
}
};

这里有一点需要澄清下,虽然我们使用friend,却与friend的传统用途“方位class的non-public成分”毫不相干。为了让类型转换可能发生于所有实参身上,我们需要一个non-member函数;为了零这个函数被自动具现化,我们需要将它声明在clss内部;而在class内部声明non-member函数的唯一办法就是:令他成为一个friend。


进一步完善,为了对inline函数的造成的冲击最小化,我们可以让其调用一个辅助函数来实现。最终版本如下:

//这是在头文件中实现的

//这个是辅助函数
template<typename T>
const Rational<T> doMultiply(cosnt Rational<T> &lhs, cosnt Raional<T> &rhs);

template<typename T>
class Rational
{
public:
    ...
    friend cosnt Rational<T> operator*(const Rational<T> &lhs, const Rational<T> &rhs)
{return doMultiply(lhs, rhs);}
};

总结:当我们编写一个class template,而它所提供之“与此template相关的”函数支持“所有参数之隐式类型转换”时,请将那些函数定义为“class template内部的friend函数”。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值