【共讀Primer】58.[6.5]參數匹配 Page217
一般來說函數的選擇是比較明確的事情,因為有著參數類型和參數數量的標準。
但是如果將類型轉換和默認參數都加入到重載函數中,這個過程就變的復雜起來。
來看看一下代碼:
void f(); void f(int); void f(int ,int); void f(double, double = 3.14);
在函數的選擇過程中分為兩步:
1. 找到當前作用域可見的所有名稱相同的函數
2. 找到參數數量相等且類型相同或可轉換的函數
f(5.6); // 調用 void f(double, double)
那麽在一些極端情況下還存在第三部:
3. 尋找最佳匹配
我們知道int和double這兩個內置類型是可以進行轉化的,所以對上面的函數調用
如果不存在void f(double, double = 3.14), 那麽void f(int) 將會被調用
這裏void f(double, double=3.14)就是最佳匹配,
那麽我們來看看一個更復雜的情況
f(42, 2.56); // 這個調用完全沒有精確的匹配函數,編譯器應該如何選擇?
我們來編碼實際操作一下:
#include <iostream> void f(){std::cout << "f()" << std::endl;}; void f(int){std::cout << "f(int)" << std::endl;};void f(int, int){std::cout << "f(int, int)" << std::endl;}; void f(double, double = 3.14){std::cout << "f(double, double = 3.14)" << std::endl;}; int main() { f(5.6); f(42, 2.56); }
對於上面的代碼編譯情況如下, 意思是編譯器也不知道改掉用哪個,兩者處於平等位置,沒有最優調用
在此類重載的選擇上的原則是
1. 每個參數匹配都不劣於其他的函數匹配。
2. 至少有一個參數的匹配優於其他函數
而本次我們寫的調用,
針對第一個參數來說f(int, int) 更匹配,但是第二個參數需要做轉換。
針對第二個參數來說f(double,double=3.14)更匹配,但是第一個參數需要轉換。
所以對於編譯器來說兩個可行函數的優劣沒有區別,無法進行更優選擇,則產生二義性錯誤。
#include <iostream> void f(){std::cout << "f()" << std::endl;}; void f(int){std::cout << "f(int)" << std::endl;}; void f(int, int){std::cout << "f(int, int)" << std::endl;}; void f(double, double = 3.14){std::cout << "f(double, double = 3.14)" << std::endl;}; int main() { f(5.6); // f(42, 2.56); }
本次代碼編譯運行結果如下:
實參類型轉換
而在參數匹配的過程中類型轉換也被劃分為幾個級別:
1. 精確匹配
以下情形屬於精確匹配 :
a. 實參類型和形參類型相同
b. 實參從數組類型或函數類型轉換成對應的指著那類型
c. 向實參添加頂層const或者從實參刪除頂層const
2. 通過const轉換實現的匹配
3. 通過類型提示鞥實現的匹配
4. 通過算術類型轉換或指針轉換實現的匹配
5. 通過類類型轉換實現的匹配
以上的所有情況從上到下的每級的匹配程度低於上一級。
在轉換過程中,遵循的原則是從小向打的轉換
如short和int的兩個匹配類型中如果都需要轉換,通常會選擇int
void ff(int); void ff(short); ff(‘a‘); // char提升為int
而在算數類型的轉換中並沒有高低的區別。
void manip(long); void manip(float); manip(3.14); // 調用將產生二義性
const和參數匹配
非const參數可以作為const實參進行傳遞,但是const實參不能作為非const參數 傳遞。
所以當一個函數有const和非const兩個版本時,那麽將根據參數的精確類型來匹配。
否則將可以使用非const實參調用const形參的函數
void lookup(Account &); void lookup(const Account&); const Account a; Account b; lookup(a); // 這個參數只能通過lookup(const Account&)來調用 lookup(b); // 這個參數兩個重載都可以調用,但lookup(Account&)匹配更精確
【共讀Primer】58.[6.5]參數匹配 Page217