模板函數的重載
普通函數可以重載,模板函數也可以重載,但規則復雜
有下面2個函數,名字相同,返回值相同就,參數不同,符合重載。
template<typename T>
std::string moban(const T& t){}
template<typename T>
std::string moban(T* p){}
調用1
std::string s("hi");
std::cout << moban(s) << std::endl;
結果1:調用的是(const T& t),這個可以簡單理解,因為參數不是指針類型,所以不適用於(T* p)。
調用2
std::string s("hi");
std::cout << moban(&s) << std::endl;
結果2:調用的是(T* p)。這個就復雜了,因為2個模板都符合,但是調用哪個呢。
- moban(const string*&) T被綁定到string*。
- moban(string*) T被綁定到string。
因為(const T& t)的實例需要進行普通指針到const指針的轉換,(T* p)不需要轉換,所以是更精准的匹配。
所以推導出規則1:更精准的匹配會被優先采用。
調用3
std::string s("hi");
const std::string* sp = &s;
std::cout << moban(sp) << std::endl;
結果3:調用的是(T* p)。這個就更復雜了,因為2個模板都符合,而且都是同樣精准的匹配,但是調用哪個呢。
- moban(const string*&) T被綁定到string*。
- moban(string*) T被綁定到const string。
在此情況下,因為是同樣精准的匹配,所以無法區分調用哪個。但是根據重載函數模板的特殊規則,調用了(T* p)。
原因是,(const T& t)本質上可以用於任何類型,包括指針類型,比(T* p)更通用,后者只能用於指針類型。
所以推導出規則2:同樣精准的話,更特殊的會被優先采用。
如果非模板函數和模板函數同時存在,構成重載,會調用哪個?
有下面3個函數,名字相同,返回值相同就,參數不同,符合重載。
template<typename T>
std::string moban(const T& t){}
template<typename T>
std::string moban(T* p){}
std::string moban(const std::string& s){}
調用4
std::string s("hi");
std::cout << moban(s) << std::endl;
結果4:調用的是非模板的函數。
- (const T& t) T被綁定到string,也是可以被調用的。
但是,非模板優先模板。
所以推導出規則3:非模板和模板同時都適用的時候,非模板的會被優先采用。
調用5
std::string s("hi");
std::cout << moban(s) << std::endl;
結果5:調用的是(T* p),而沒有調用非模板函數。
所以看出來,規則3有個特例,就是,如果模板的匹配比非模板的匹配更精准的時候,模板會被優先采用。
- moban(const T& t) T被綁定到char[2]。
- moban(T*) T被綁定到const char。
- moban(const std::string& s) 要求從const char*到string的類型轉換。
理由:非模板也是可行的,但是需要進行一次用戶定義的類型轉換,因此她沒有模板的匹配更精准。但是2個模板都可以被調用,但是(T*)更特例化,所以最好調用的是(T*)
所以推導出規則4:非模板和模板同時都適用的時候,非模板如果需要一次用戶定義的類型轉換,而模板不需要的話,模板會被優先采用。
非模板函數和模板函數的聲明位置,導致結果的不同。
有下面4個函數,名字相同,返回值相同就,參數不同,符合重載。
template<typename T>
std::string moban(const T& t){}
template<typename T>
std::string moban(T* p){}
std::string moban(const char* p){
return debug_rep(std::string(p));
}
std::string moban(const std::string& s){}
調用5
std::cout << moban("hello") << std::endl;