您的位置:首页 > 编程语言 > C语言/C++

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

2015-06-05 15:01 405 查看
背景:承接条款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函数”。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: