模板是C++中简单但是非常实用的工具,简单是指我们可以通过将数据类型作为参数从而对于不同的数据类型我们不必写相同的代码
How do templates work?
模板在编译期会被扩展,这一点有点像宏,不同的是模板在编译期扩展的时候会做类型检查。模板的思路是比较简单的,一般源码只包含函数/类,但模板扩展后可能包含多份函数/类的拷贝
函数模板: 使用模板编写可以编写用于多种数据类型的通用函数
#include <iostream>
using namespace std;
// One function works for all data types. This would work
// even for user defined types if operator '>' is overloaded
template <typename T>
T myMax(T x, T y)
{
return (x > y)? x: y;
}
int main()
{
cout << myMax<int>(3, 7) << endl; // Call myMax for int
cout << myMax<double>(3.0, 7.0) << endl; // call myMax for double
cout << myMax<char>('g', 'e') << endl; // call myMax for char
return 0;
}
类模板: 与函数模板类似,当类的定义不依赖具体类型时类模板是非常有用的
#include <iostream>
using namespace std;
template <typename T>
class Array {
private:
T *ptr;
int size;
public:
Array(T arr[], int s);
void print();
};
template <typename T>
Array<T>::Array(T arr[], int s) {
ptr = new T[s];
size = s;
for(int i = 0; i < size; i++)
ptr[i] = arr[i];
}
template <typename T>
void Array<T>::print() {
for (int i = 0; i < size; i++)
cout<<" "<<*(ptr + i);
cout<<endl;
}
int main() {
int arr[5] = {1, 2, 3, 4, 5};
Array<int> a(arr, 5);
a.print();
return 0;
}
Can there be more than one arguments to templates?
是的,像正常的参数,我们可以传递多个参数作为模板参数
#include<iostream>
using namespace std;
template<class T, class U>
class A {
T x;
U y;
public:
A() { cout<<"Constructor Called"<<endl; }
};
int main() {
A<char, char> a;
A<int, double> b;
return 0;
}
Can we specify default value for template arguments?
是的,像一般的参数,模板可以指定默认的类型,但需要注意的是可以省略指定数据类型的默认类型需要靠后放置
#include<iostream>
using namespace std;
template<class T, class U = char>
class A {
public:
T x;
U y;
A() { cout<<"Constructor Called"<<endl; }
};
int main() {
A<char> a; // This will call A<char, char>
return 0;
}
What is the difference between function overloading and templates?
函数重载和模板都是面向对象编程中多态的实现方式,函数重载通常用于多个函数实现类似的操作,而模板通常用于多个函数实现相同的操作
What happens when there is a static member in a template class/function?
每一个模板实例都会包含它所有的静态变量
#include <iostream>
using namespace std;
template <class T> class Test
{
private:
T val;
public:
static int count;
Test()
{
count++;
}
// some other stuff in class
};
template<class T>
int Test<T>::count = 0;
int main()
{
Test<int> a; // value of count for Test<int> is 1 now
Test<int> b; // value of count for Test<int> is 2 now
Test<double> c; // value of count for Test<double> is 1 now
cout << Test<int>::count << endl; // prints 2
cout << Test<double>::count << endl; //prints 1
getchar();
return 0;
}
What is template specialization?
模板特例化允许我们对于不同类型有不同的实现
// A generic sort function
template <class T>
void sort(T arr[], int size)
{
// code to implement Quick Sort
}
// Template Specialization: A function
// specialized for char data type
template <>
void sort<char>(char arr[], int size)
{
// code to implement counting sort
}
#include <iostream>
using namespace std;
template <class T>
class Test
{
// Data members of test
public:
Test()
{
// Initialization of data members
cout << "General template object \n";
}
// Other methods of Test
};
template <>
class Test <int>
{
public:
Test()
{
// Initialization of data members
cout << "Specialized template object\n";
}
};
int main()
{
Test<int> a;
Test<char> b;
Test<float> c;
return 0;
}
Can we pass nontype parameters to templates?
我们可以给模板设置非类型的参数,非类型参数通常用于给模板特殊实例指定最大、最小或任意常量值,对于非类型参数重要的一点是参数必须是const类型。在编译期间,编译器必须能够知道非类型数据的值,因为在编译期间编译器需要为非类型数据创建函数/类
// A C++ program to demonstrate working of non-type
// parameters to templates in C++.
#include <iostream>
using namespace std;
template <class T, int max>
int arrMin(T arr[], int n)
{
int m = max;
for (int i = 0; i < n; i++)
if (arr[i] < m)
m = arr[i];
return m;
}
int main()
{
int arr1[] = {10, 20, 15, 12};
int n1 = sizeof(arr1)/sizeof(arr1[0]);
char arr2[] = {1, 2, 3};
int n2 = sizeof(arr2)/sizeof(arr2[0]);
// Second template parameter to arrMin must be a constant
cout << arrMin<int, 10000>(arr1, n1) << endl;
cout << arrMin<char, 256>(arr2, n2);
return 0;
}
What is template metaprogramming?
#include <iostream>
using namespace std;
template<int n> struct funStruct
{
enum { val = 2*funStruct<n-1>::val };
};
template<> struct funStruct<0>
{
enum { val = 1 };
};
int main()
{
cout << funStruct<8>::val << endl;
return 0;
}