欢迎光临散文网 会员登陆 & 注册

需要类型转换的函数

2023-01-16 00:53 作者:sxlxcsxlxc  | 我要投稿

effective c++ 3rd 24&46

如果我们写了这样一个有理数类

构造函数没有声明成explicit,也就是说我们支持从各种数据类型隐式转换到rational,同时注意到numerator和denominator的默认值,int x会被转换成大小相等的分数x/1. 

此时我们应该定义一下rational的乘法,由于已经支持了类型的隐式转换,我们很自然的想要让乘法也能在rational和其他数据类型之间进行。由于是给rational定义的乘法,我们又自然的想要operator*定义成rational的一个成员函数。

这时问题出现了,rational*int工作正常,然而int*rational却无法通过编译,我们的乘法应该符合交换律,这说明operator*定义成rational的一个成员函数是不行的,我们需要把operator*放在外面。

下面我们考虑把rational变成一个模板类(为什么要这样做?按照我浅薄的理解,任何东西写成template可能会带来两个好处:代码重用和让编译器发现和类型有关的各种错误。在这个例子里,可能是不同的int类型的重用,int, long long, mpz_class...)

我们考虑当rational变成一个模板类之后会发生什么。

首先有一个问题,友元函数print该如何定义。。。

最简单的方法是:

但是如果我们想把模板类的友元函数定义写在类的定义的外面,问题就出现了。print函数是模板类的友元,对rational的每个特化都存在一份print,但是print本身并不是模板函数。我没有想出什么办法能够在类外定义一个非模板函数友元。

参考: https://stackoverflow.com/questions/52749225/what-is-the-right-way-to-define-a-friend-function-outside-a-template-class

此外我们还需要考虑怎么定义operator*,也许我们会写成下面这样:

然而这并不是很合理,因为此时operator*已经是一个模板函数了,此时我们如果写出 rational<int>*int这样的表达式,编译器会说template argument deduction/substitution failed。

这是因为对于模板函数的operator*,rational*int首先要做的是模板参数推导,对于lhs他确实是一个rational<int>,但是对于rhs,推导出的类型就是int,并不会管rational类是否支持隐式类型转换,这就产生了问题。

我们想到解决这个问题的一个方法就是不能让operator*是模板函数,那我们就让他变成一个友元函数,对每个特化的rational都生成一份operator*的代码,没有模板参数推导的过程就不会产生问题。


需要类型转换的函数的评论 (共 条)

分享到微博请遵守国家法律