C++模板详解
模板是C++中实现泛型编程的重要特性,它允许你编写与数据类型无关的代码。模板可以分为函数模板和类模板两种。
1. 函数模板
函数模板允许你定义一个可以处理多种数据类型的函数。
基本语法
template <typename T>
T functionName(T parameter1, T parameter2, ...) {
// 函数体
}
示例
#include <iostream>
// 函数模板示例:返回两个值中的较大者
template <typename T>
T max(T a, T b) {
return (a > b) ? a : b;
}
int main() {
std::cout << max<int>(3, 7) << std::endl; // 输出 7
std::cout << max<double>(3.2, 7.5) << std::endl; // 输出 7.5
std::cout << max<char>('a', 'z') << std::endl; // 输出 z
// 编译器可以自动推导类型
std::cout << max(3, 7) << std::endl; // 输出 7
std::cout << max(3.2, 7.5) << std::endl; // 输出 7.5
return 0;
}
2. 类模板
类模板允许你定义一个可以处理多种数据类型的类。
基本语法
template <typename T>
class ClassName {
// 类成员
};
示例
#include <iostream>
// 类模板示例:简单的数组类
template <typename T, int size>
class Array {
private:
T arr[size];
public:
void set(int index, T value) {
if (index >= 0 && index < size) {
arr[index] = value;
}
}
T get(int index) const {
if (index >= 0 && index < size) {
return arr[index];
}
return T(); // 返回默认值
}
void print() const {
for (int i = 0; i < size; ++i) {
std::cout << arr[i] << " ";
}
std::cout << std::endl;
}
};
int main() {
Array<int, 5> intArray;
intArray.set(0, 10);
intArray.set(1, 20);
intArray.set(2, 30);
intArray.print(); // 输出: 10 20 30 0 0
Array<double, 3> doubleArray;
doubleArray.set(0, 3.14);
doubleArray.set(1, 2.71);
doubleArray.print(); // 输出: 3.14 2.71 0
return 0;
}
3. 模板特化
模板特化允许你为特定类型提供特殊的实现。
示例:函数模板特化
#include <iostream>
#include <cstring>
// 通用模板
template <typename T>
void print(T value) {
std::cout << "General: " << value << std::endl;
}
// 特化版本 for const char*
template <>
void print<const char*>(const char* value) {
std::cout << "Specialized for const char*: " << value << std::endl;
}
int main() {
print(10); // 调用通用版本
print(3.14); // 调用通用版本
print("Hello"); // 调用特化版本
return 0;
}
示例:类模板特化
#include <iostream>
// 通用类模板
template <typename T>
class Printer {
public:
void print(T value) {
std::cout << "General: " << value << std::endl;
}
};
// 特化版本 for bool
template <>
class Printer<bool> {
public:
void print(bool value) {
std::cout << "Specialized for bool: " << (value ? "true" : "false") << std::endl;
}
};
int main() {
Printer<int> intPrinter;
intPrinter.print(42); // 输出: General: 42
Printer<bool> boolPrinter;
boolPrinter.print(true); // 输出: Specialized for bool: true
return 0;
}
4. 可变参数模板
C++11引入了可变参数模板,允许模板接受任意数量和类型的参数。
示例
#include <iostream>
// 基础情况:没有参数时
void print() {
std::cout << std::endl;
}
// 可变参数模板
template <typename T, typename... Args>
void print(T first, Args... args) {
std::cout << first << " ";
print(args...); // 递归调用
}
int main() {
print(1, 2.5, "Hello", 'a'); // 输出: 1 2.5 Hello a
return 0;
}
5. 模板元编程
模板可以在编译时进行计算,这被称为模板元编程。
示例:编译时阶乘计算
#include <iostream>
// 模板元编程示例:编译时计算阶乘
template <int N>
struct Factorial {
static const int value = N * Factorial<N - 1>::value;
};
// 特化:基本情况
template <>
struct Factorial<0> {
static const int value = 1;
};
int main() {
std::cout << "Factorial of 5: " << Factorial<5>::value << std::endl; // 输出 120
return 0;
}
6. 模板的注意事项
- 分离编译问题:模板的定义通常需要放在头文件中,因为编译器需要看到完整的定义才能实例化模板。
- 类型推导:编译器可以自动推导模板参数类型,但有时需要显式指定。
- 性能:模板不会带来运行时开销,因为所有工作都在编译时完成。
- 代码膨胀:每个不同的模板实例化都会生成新的代码,可能导致二进制文件变大。
模板是C++强大而复杂的特性,合理使用可以大大提高代码的复用性和灵活性。