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

模板函数和非模板函数

template<typename T>
T Mul(T a, T b)
{
	return a * b;
}

double Add (double a, double b)
{
	return a+b;
}
int main()
{
	float a = 1.0f;
	double b = 2.0;
	//Mul(a, b); error
	Add(a, b);
}

可以看到Mul(a,b)在编译的时候报错,报错原因是找不到Mul(float, double)这个函数,可以Add就没有问题,所以编译器对待模板函数和非模板函数是完全不一样:模板必须找到一个完全一样的实例化函数,而非模板函数则可以自动隐式类型转换,原因是只有一个实例化函数后才可以进行参数类型转换,但是模板函数在实例化一个函数时候都失败了,所以更不要提后续隐形类型转换了。

模板类

先看一个例子:

template<typename T>
class Rational
{
}
template<typename T>
Rational<T> operator* (const Rational<T>& l, const Rational<T>& r) {...};

这个代码我们分析一下:

Rational<int> one;
Rational<int> res = one * 2//error

报错原因和上面一样,在实例化一个函数的时候,找不到operator*(Rational,int)的函数,所以也谈不上类型转换,下面给一个解决方案:

template<typename T>
class Rational
{
  public:
  	Rational(int);
	friend Rational<T> operator* (const Rational<T>& l, const Rational<T>& r);
};

template<typename T>
Rational<T> operator* (const Rational<T>& l, const Rational<T>& r) {};

Rational<int> one(1);
Rational<int> res = one * 2;//right
/********       compile       ***********/
/* First instantiated from: insights.cpp:18 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
class Rational<int>
{
  public: 
  Rational(int);
  friend Rational<int> operator*(const Rational<int> & l, const Rational<int> & r);
};
#endif

template<typename T>
Rational<T> operator*(const Rational<T> & l, const Rational<T> & r){};

Rational<int> one = Rational<int>(1);
Rational<int> res = operator*(one, Rational<int>(2));

根据上面的编译结果可以看出来,在one是实例化的时候,Rational的代码也自动生成了,对应的Rational operator也声明出来了,所以编译时候也就可以自动转换,但是这个代码只能编译成功却没办法运行,我们在仔细看看operator(one, Rational(2))这一行代码,可是我们在上面的编译后代码依然找不到这个函数的具体定义,因为Rational operator*(const Rational & l, const Rational & r){};依然没有实例化,怎么办?

template<typename T>
class Rational
{
  public:
  	Rational(int);
	friend Rational<T> operator* (const Rational<T>& l, const Rational<T>& r)
	{
		return l.value * r.value;
	};
};

这个代码很有意思,首先为了让所有参数可以自动类型转换,所以函数必须是non-member 函数,而由于是模板,所以在对象实例化的时候函数也必须生成,这样只能是一个friend。很骚。
上面的解决方法因为是直接定义在class中,所以会暗自称为inline函数,为了减少inline的负面影响,这里可以让operator*什么都不做,调用一个外面的函数。

//文件1
template<typename T>
class Rational;

template<typename T>
Rational<T> DoSomething(const Rational<T>& l, const Rational<T>& r)
{
	do something;
	return res;
};

template<typename T>
class Rational
{
  public:
  	Rational(int);
	friend Rational<T> operator* (const Rational<T>& l, const Rational<T>& r)
	{
		return DoSomething(l,r);
	};
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值