函数模板的重载
#include <cstring> #include <iostream> #include <typeinfo> using namespace std; template<typename T> T const& max (T const& x, T const& y) { cout << "<1" << typeid (x).name () << '>' << flush; return x < y ? y : x; } char const* const& max (char const* const& x, char const* const& y) { cout << "<2" << typeid (x).name () << '>' << flush; return strcmp (x, y) < 0 ? y : x; } /* char const* max (char const* x, const char* y) { return strcmp (x, y) < 0 ? y : x; } */ template<typename T> T* const& max (T* const& x, T* const& y) { cout << "<3" << typeid (x).name () << '>' << flush; return *x < *y ? y : x; } template<typename T> T const& max (T const& x, T const& y, T const& z) { cout << "<4" << typeid (x).name () << '>' << flush; return ::max (::max (x, y), z); } /* char const* const& max (char const* const& x, char const* const& y) { cout << "<2" << typeid (x).name () << '>' << flush; return strcmp (x, y) < 0 ? y : x; } */ int main (void) { cout << ::max (123, 456) << endl; cout << ::max (1.23, 4.56) << endl; cout << ::max<string> ("hello", "world") << endl; cout << ::max ("hello", "world") << endl; int x = 123, y = 456; cout << *::max (&x, &y) << endl; char const* a = "ABC"; char const* b = "AB"; char const* c = "A"; // 编译器优先选择普通函数 cout << ::max (a, b) << endl; // 2 // 除非函数模板能够产生具有更好匹配性的函数 int d = 100, e = 200; cout << ::max (d, e) << endl; // 1 // 在参数传递过程中如果需要隐式类型转换,编译器 // 只能选择普通函数 cout << ::max (a, (char*)b) << endl; // 2 // 通过模板参数表告知编译器使用函数模板 // 针对指针的版本显然比任意类型版本更加具体 cout << ::max<> (b, a) << endl; // 3 // 显式指定的模板参数必须在所选择的重载版本中与 // 调用参数的类型保持一致 cout << ::max<char const*> (b, a) << endl; // 1 cout << ::max (123, 789, 456) << endl; // 在函数模板的实例化函数中,编译器优先选择普通 // 函数,但是该普通函数必须声明于模板之前 cout << ::max (a, b, c) << endl; char const* const& r = max (a, b, c); cout << r << endl; // ABC char const* g = "123"; char const* h = "12"; char const* i = "1"; max (g, h, i); cout << r << endl; // ABC return 0; }
一次编译和二次编译:
重载选择的时机问题:
模板在第一次编译时,会生成模板函数的内部表示,二次编译实例化模板,此时生成具体指令,确定重载版本,参数类型T具体类型已经知道。
但是可供选择的普通函数或者模板函数必须声明于该模板函数之前。因为,单向编译器在二次编译确定选择哪一个,但具体选择范围在一次编译时确定。在一次编译时,编译到该模板时只能看见其前面的重载版本。