需要類型轉(zhuǎn)換的函數(shù)
effective c++?3rd 24&46
如果我們寫了這樣一個(gè)有理數(shù)類
構(gòu)造函數(shù)沒有聲明成explicit,也就是說我們支持從各種數(shù)據(jù)類型隱式轉(zhuǎn)換到rational,同時(shí)注意到numerator和denominator的默認(rèn)值,int x會被轉(zhuǎn)換成大小相等的分?jǐn)?shù)x/1.?
此時(shí)我們應(yīng)該定義一下rational的乘法,由于已經(jīng)支持了類型的隱式轉(zhuǎn)換,我們很自然的想要讓乘法也能在rational和其他數(shù)據(jù)類型之間進(jìn)行。由于是給rational定義的乘法,我們又自然的想要operator*定義成rational的一個(gè)成員函數(shù)。
這時(shí)問題出現(xiàn)了,rational*int工作正常,然而int*rational卻無法通過編譯,我們的乘法應(yīng)該符合交換律,這說明operator*定義成rational的一個(gè)成員函數(shù)是不行的,我們需要把operator*放在外面。
下面我們考慮把rational變成一個(gè)模板類(為什么要這樣做?按照我淺薄的理解,任何東西寫成template可能會帶來兩個(gè)好處:代碼重用和讓編譯器發(fā)現(xiàn)和類型有關(guān)的各種錯誤。在這個(gè)例子里,可能是不同的int類型的重用,int, long long, mpz_class...)
我們考慮當(dāng)rational變成一個(gè)模板類之后會發(fā)生什么。
首先有一個(gè)問題,友元函數(shù)print該如何定義。。。
最簡單的方法是:
但是如果我們想把模板類的友元函數(shù)定義寫在類的定義的外面,問題就出現(xiàn)了。print函數(shù)是模板類的友元,對rational的每個(gè)特化都存在一份print,但是print本身并不是模板函數(shù)。我沒有想出什么辦法能夠在類外定義一個(gè)非模板函數(shù)友元。
參考: https://stackoverflow.com/questions/52749225/what-is-the-right-way-to-define-a-friend-function-outside-a-template-class
此外我們還需要考慮怎么定義operator*,也許我們會寫成下面這樣:
然而這并不是很合理,因?yàn)榇藭r(shí)operator*已經(jīng)是一個(gè)模板函數(shù)了,此時(shí)我們?nèi)绻麑懗?rational<int>*int這樣的表達(dá)式,編譯器會說template argument deduction/substitution failed。
這是因?yàn)閷τ谀0搴瘮?shù)的operator*,rational*int首先要做的是模板參數(shù)推導(dǎo),對于lhs他確實(shí)是一個(gè)rational<int>,但是對于rhs,推導(dǎo)出的類型就是int,并不會管rational類是否支持隱式類型轉(zhuǎn)換,這就產(chǎn)生了問題。
我們想到解決這個(gè)問題的一個(gè)方法就是不能讓operator*是模板函數(shù),那我們就讓他變成一個(gè)友元函數(shù),對每個(gè)特化的rational都生成一份operator*的代碼,沒有模板參數(shù)推導(dǎo)的過程就不會產(chǎn)生問題。