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

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


只有非成员函数才有能力“在所有实参身上实施隐式类型转换”,该条款可以通过Rational(有理数)类和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> operator*(const Rational<T>& lhs,
                            const Rational<T>& rhs)
{...}


我们希望支持混合式算数运算,即:
Rational<int> oneHalf(1,2);


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


上述失败给我们的启示是,模板化的Rational里的某些东西似乎和他的非模板版本不同,在这里编译器不知道我们想要调用哪个函数。取而代之的是它们试图想出什么函数被命名为operator*的模板具现化(产生)出来。它们知道它们可以具现化某个“名为operator*并接受两个Rational<T>参数”的函数。但为完成这一具现化行为,必须先算出T是什么,问题的它没有这个能耐。








只要利用一个事实,我们就可以缓和编译器在模板参数推导方面受到的挑战:模板类里的友元声明式可以指涉某个特定函数。那意味着类 Rational<T>可以声明operator*是它的一个友元函数。类模板并不依赖模板实参推导(后者只施行于函数模板身上),所以编译器总是能够在类Rational<T>具现化时得知T,因此令Rational<T>类声明适当的operator*为其友元函数,可简化整个问题:






template<typename T>
class Rational
{
public:
  ...
  friend
  const Rational operator*(const Rational<T>& lhs,//声明operator*函数
                           const Rational<T>& rhs);
};


template<typename T>
const Rational<T> operator*(const Rational<T>& lhs,//定义operator*函数
                            const Rational<T>& rhs)
{...}


现在对operator*的混合调用可以通过编译了,






我们可以将operator*函数本体合并至其声明式中:


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


这项技术的特点是,我们虽然使用友元,却与友元的传统用途“访问类的非公有成分”毫不相干。为了让转型可能发生于所有实参身上,我们需要一个非成员函数;为了让类型转换可能发生于所有实参身上,我们需要一个非成员函数;为了让这个函数被自动具现化,我们需要将他声明在类内部,而在类里声明非成员函数的唯一办法就是:令他成为一个友元,因此我们就这样做了。










注意:
当我们编写一个类模板时,而他所提供的“与此模板相关的”函数支持“所有参数的隐式类型转换”的时候,请将那些函数定义为“类模板内部的友元函数”。


























































































阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页