Effecticve学习笔记_条款46:需要类型转换时请为模板定义非成员函数

原创 2016年08月31日 11:52:34

  条款24已经讨论过为什么惟有non-member函数才有能力“在所有实参身上实施隐式类型转换”,这里还以Rational class的operator*函数为例。
  这里将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> opearator* (const Rational<T>& lhs, const Rational<T>& rhs) 
{......}

  下面的例子如同条款24一样,唯一不同的是Rational和operator*如今都变成了templates:

Rational<int> oneHalf(1,2); //这个例子来自条款24
Rational<int> result = oneHalf * 2; // 错误,无法通过编译

  上述过程无法通过编译,因为编译器这里不知道我们想要调用哪个函数。取而代之的是,它们试图想出什么函数被名为operator* 的template具现化(产生)出来。它们知道它们应该可以具现化某个“名为operator*并接受两个Rational< T >参数”的函数,但为完成这一具现化行动,必须先算出T是什么。
  以oneHalf进行推导,过程并不困难。operator* 的第一参数被声明为Rational< T >,而传递给operator* 的第一实参(oneHalf)的类型是Rational< int >,所以T一定是int。其他参数的推导则没有这么顺利。operator* 的第二参数被声明为Rational< T >,但传递给operator* 的第二实参(2)类型是int。由于template实参推导过程中从不将隐式类型转换函数纳入考虑,所以这里编译器并不会将2转换为Rational< int >,进而将T推导为int。一句话,隐式转换+推导T不能被同时被编译器接受。
  解决问题的思路便接着产生,编译器既然不能同时接受这两个过程,就让它们事先满足好一个条件,再由编译器执行另一个过程好了。
  如果把这个operator*放在template class里面,也就是先在生成模板类的那一步就定下T,这样编译器只要执行隐式转换这一步就可以了。
  因此我们可以这样来改:
  

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

template <class T>
const Rational<T> operator* (const Rational<T>& lhs, const Rational<T>& rhs)
{
    // 这里友元函数的声明并不是用来访问类的私有成员的,而是用来进行事先类型推导的
    return Rational<T>(lhs.numerator() * rhs.numerator(), 
        lhs.denominator() * rhs.denominator());
}

  注意中间我们添加了一个友元函数。果然编译通过了,但链接时又报错了,原因是链接器找不到operator*的定义,这里又要说模板类中的一个特殊情况了,它不同与普通的类,模板类的友元函数只能在类中实现,所以要把函数体部分移至到类内,像下面这样:

template <class T>
class Rational
{
    …
    friend Rational operator* (const Rational& lhs, const Rational& rhs)
    {
        return Rational(lhs.numerator() * rhs.numerator(), 
        lhs.denominator() * rhs.denominator());
     }
    …
}

  这下编译和链接都没有问题了。这里还要说一下,就是移至类内后,T的标识符可以不写了,但如果非要写成下面这样,自然也是OK的。

friend Rational operator* (const Rational& lhs, const Rational& rhs)
{
    return Rational(lhs.numerator() * rhs.numerator(), 
    lhs.denominator() * rhs.denominator());
}

  operator* 里面只有一句话,但如果friend函数里面的东西太多了,可以定义一个辅助方法,比如DoMultiply(),这个DoMultiply可以放在类外去实现,DoMultiply本身不支持混合乘法(2 * SomeRational或者SomeRational * 2),但由于在operator*里面已经进行了隐式类型转换,所以到DoMultiply这一级是没有问题的。
  
  总结:当我们编写一个class template,而它所提供之“与此template相关的”函数支持“所有参数之隐式类型转换”时,请将那些函数定义为“class template内部的friend函数”。

版权声明:本文为博主原创文章,未经博主允许不得转载。

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

Item 46: Define non-member functions inside templates when type conversions are desired.Item 24中提到...
  • dongyu_1989
  • dongyu_1989
  • 2018年02月10日 20:01
  • 11

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

(一) 首先我们回顾条款24,它说过为什么惟有non-member函数才有能力“在所有实参身上实施隐式类型转换”。 现在我们将Rational和operator*模板化: template cl...
  • u010470972
  • u010470972
  • 2014年09月23日 22:09
  • 500

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

条款46:需要类型转换时请为模板定义非成员函数    Define non-member functions inside templates when type conversion are des...
  • scofieldzhu
  • scofieldzhu
  • 2009年10月21日 21:09
  • 787

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

/*条款46:需要类型转换时请为模板定义非成员函数*/ #include using namespace std; template class Rational{ public: Rational...
  • sbfksmq
  • sbfksmq
  • 2015年09月28日 16:06
  • 199

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

template class Rational; template const Rational doMultiply(const Rational& lhs, const Rational& rhs...
  • zhliu1991
  • zhliu1991
  • 2014年09月19日 12:09
  • 257

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

经验:当我们编写一个 class template, 而它所提供之"与此 template 相关的"函数支持"所有参数之隐式类型转换"时,请将那些函数定义为 "class template内部的 fr...
  • zhsenl
  • zhsenl
  • 2014年07月14日 09:06
  • 630

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

背景:承接条款24条(请先去了解),那么,之于template实现版本呢? template class Rational { public: Rational(const T& numer...
  • xujiali5172923
  • xujiali5172923
  • 2015年06月05日 15:01
  • 341

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

我们在Item 24提到过用将Rational的operator*声明为non-member,从而使2*oneHalf得以成功调用该函数。这是在没有template的情况下。Rational和oper...
  • forlove_you
  • forlove_you
  • 2017年03月28日 19:19
  • 66

C++之需要类型转换时请为模板定义非成员函数(46)---《Effective C++》

条款46:需要类型转换时请为模板定义非成员函数请将这篇文章和条款24对比学习,可以更好地理解这篇文章的主题,条款24主要介绍了“non-member函数才可以对实参进行隐式转换的能力”,具体举例是自定...
  • u014038273
  • u014038273
  • 2017年08月15日 11:33
  • 82

effective cpp24, 46需要类型转换时请为模板定义非成员函数

一般看来,令class支持隐式转换是不好的实现。但在混合运算中更适合支持混合运算。 class Rational { public: Rational(int numerator = 0...
  • qq_25310869
  • qq_25310869
  • 2017年08月19日 11:09
  • 73
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Effecticve学习笔记_条款46:需要类型转换时请为模板定义非成员函数
举报原因:
原因补充:

(最多只允许输入30个字)