Templates¶
约 120 个字 105 行代码 预计阅读时间 2 分钟
Ambiguous Function Overload¶
void foo(int i) {}
void foo(double d){}
foo(10L); // Compile error. Ambiguous! long can convert to both i and d implicitly
Template Instantiation¶
Compilers help you to overload a function.
Only when the template function/class is called/instantiated with specialized types, will it be created to a specialized type of code by compilers.
template <class T>
void print(T a, T b){
cout << a << " " << b << endl;
}
void print(string a, string b){
cout << a << " " << b << endl;
}
int a = 1, b = 2, c = 3;
float d = 1.0, e = 2.0;
print(a, b); // Create a int type my_swap
print(b, c); // Use the already created int type my_swap
print(d, e); // Create a float type my_swap
print(a, d); // Compile error. Implicit type conversion is not allowed in templates.
print<double>(a, d); // Good!
print("a", "b"); // Call the normal funtion!
-
Which function to use?
-
Compilers will exact match for normal function first (no implicit type conversion).
-
Then match for templates.
-
Then match for normal function. (with implicit type conversion).
example:
template <class T1, class T2> void foo(T1 a, T2 b){ cout << "foo(T1, T2)" << endl; } void foo(int a, double b){ cout << "foo(int, double)" << endl; } int main(){ foo(1, 1.0); foo(1, 1.0f); } /* output: foo(int, double) foo(T1, T2) */
-
None-type Template Parameters¶
example
template<class T, int N = 100>
class Array{
public:
int size() const {return N;}
// ... ...
};
Array<int> arr1;
Array<int, 50> arr2; // Not the same type as arr1
Template Member Function¶
template <class T>
class A{
public:
T val;
A(T v): val(v){}
template <class U> A(const A<U>& other) : val(other.val){}
// A(const A& other) : val(other.val) {} Error ! (*this) is A<double>, (other) is A<int>
};
int main(){
A<int> a(2);
A<double> b = a;
}
Template & Inheritance ¶
- Template class can inherits from non-template class.
-
Template class can inherits from template class.
template <class C> class A : public B<C> { /* ... */ } // Here B's template parameter can be a fake type.
-
Non-template class can inherits from instantiated template class.
class A : public B<int> { /* ... */ } // Here B's template parameter is a real type.
Recurring Template¶
manually implement virtual function , just work as virtual function.
There are no vptr-table anymore, more efficient than virtual functions!
template <class T>
struct Base{
void interface(){
static_cast<T*>(this)->implementation_a();
static_cast<T*>(this)->implementation_b();
}
};
struct Derived1 : Base<Derived1>{
void implementation_a(){
std::cout << "Derived1 implementation_a\n";
}
void implementation_b(){
std::cout << "Derived1 implementation_b\n";
}
};
struct Derived2 : Base<Derived2>{
void implementation_a(){
std::cout << "Derived2 implementation_a\n";
}
void implementation_b(){
std::cout << "Derived2 implementation_b\n";
}
};
template <class T>
void foo(Base<T>& b){
b.interface();
}
int main(){
Derived1 d1;
Derived2 d2;
foo(d1);
foo(d2);
return 0;
}