模板概述
模板是C++实现泛型编程的核心特性,允许编写与数据类型无关的通用代码。
主要优势:
-
代码复用
-
类型安全
-
编译时多态
-
性能优化(编译时展开)
函数模板
基本语法
template <typename T>
T add(T a, T b) {
return a + b;
}
完整示例
#include <iostream>
#include <string>
// 1. 基本函数模板
template <typename T>
T max(T a, T b) {
return (a > b) ? a : b;
}
// 2. 多个类型参数的模板
template <typename T1, typename T2>
auto addMixed(T1 a, T2 b) -> decltype(a + b) {
return a + b;
}
// 3. 非类型模板参数
template <typename T, int size>
T scale(T value) {
return value * size;
}
// 4. 模板函数重载
template <typename T>
void print(const T& value) {
std::cout << "Generic: " << value << std::endl;
}
// 字符串特化(函数重载实现)
void print(const char* str) {
std::cout << "String: \"" << str << "\"" << std::endl;
}
void testFunctionTemplates() {
std::cout << "=== 函数模板测试 ===" << std::endl;
// 测试基本模板
std::cout << "max(3, 5) = " << max(3, 5) << std::endl;
std::cout << "max(3.14, 2.71) = " << max(3.14, 2.71) << std::endl;
std::cout << "max('a', 'z') = " << max('a', 'z') << std::endl;
// 测试混合类型
std::cout << "addMixed(10, 3.14) = " << addMixed(10, 3.14) << std::endl;
// 测试非类型参数
std::cout << "scale<int, 5>(10) = " << scale<int, 5>(10) << std::endl;
// 测试函数重载
print(42);
print(3.14159);
print("Hello Template!");
}
输出结果:
=== 函数模板测试 ===
max(3, 5) = 5
max(3.14, 2.71) = 3.14
max('a', 'z') = z
addMixed(10, 3.14) = 13.14
scale<int, 5>(10) = 50
Generic: 42
Generic: 3.14159
String: "Hello Template!"
类模板
基本语法
template <typename T>
class Container {
private:
T element;
public:
Container(T value) : element(value) {}
T get() { return element; }
};
完整示例
#include <iostream>
#include <vector>
#include <string>
// 1. 简单的栈类模板
template <typename T, int MAX_SIZE = 100>
class Stack {
private:
T data[MAX_SIZE];
int top;
public:
Stack() : top(-1) {}
bool push(const T& item) {
if (top >= MAX_SIZE - 1) return false;
data[++top] = item;
return true;
}
bool pop() {
if (top < 0) return false;
--top;
return true;
}
T peek() const {
if (top < 0) throw std::runtime_error("Stack is empty");
return data[top];
}
bool isEmpty() const { return top == -1; }
int size() const { return top + 1; }
void print() const {
std::cout << "Stack[";
for (int i = 0; i <= top; ++i) {
std::cout << data[i];
if (i < top) std::cout << ", ";
}
std::cout << "]" << std::endl;
}
};
// 2. 键值对模板
template <typename KeyType, typename ValueType>
class Pair {
private:
KeyType key;
ValueType value;
public:
Pair(KeyType k, ValueType v) : key(k), value(v) {}
KeyType getKey() const { return key; }
ValueType getValue() const { return value; }
void setValue(ValueType v) { value = v; }
void print() const {
std::cout << "{" << key << ": " << value << "}" << std::endl;
}
};
// 3. 智能指针(简化版)
template <typename T>
class SmartPtr {
private:
T* ptr;
public:
explicit SmartPtr(T* p = nullptr) : ptr(p) {}
~SmartPtr() { delete ptr; }
// 禁止拷贝构造和赋值
SmartPtr(const SmartPtr&) = delete;
SmartPtr& operator=(const SmartPtr&) = delete;
// 移动语义
SmartPtr(SmartPtr&& other) noexcept : ptr(other.ptr) {
other.ptr = nullptr;
}
SmartPtr& operator=(SmartPtr&& other) noexcept {
if (this != &other) {
delete ptr;
ptr = other.ptr;
other.ptr = nullptr;
}
return *this;
}
T& operator*() const { return *ptr; }
T* operator->() const { return ptr; }
explicit operator bool() const { return ptr != nullptr; }
};
void testClassTemplates() {
std::cout << "\n=== 类模板测试 ===" << std::endl;
// 测试Stack
Stack<int, 5> intStack;
intStack.push(1);
intStack.push(2);
intStack.push(3);
std::cout << "整数栈: ";
intStack.print();
std::cout << "栈顶元素: " << intStack.peek() << std::endl;
Stack<std::string> strStack;
strStack.push("Hello");
strStack.push("World");
strStack.push("Template");
std::cout << "字符串栈: ";
strStack.print();
// 测试Pair
Pair<std::string, int> student("Alice", 95);
Pair<int, double> dataPoint(1, 3.14159);
std::cout << "学生信息: ";
student.print();
std::cout << "数据点: ";
dataPoint.print();
// 测试SmartPtr
SmartPtr<int> smartInt(new int(42));
std::cout << "智能指针值: " << *smartInt << std::endl;
SmartPtr<std::string> smartStr(new std::string("Smart Pointer"));
std::cout << "智能指针字符串: " << *smartStr << std::endl;
std::cout << "字符串长度: " << smartStr->length() << std::endl;
}
输出结果:
=== 类模板测试 ===
整数栈: Stack[1, 2, 3]
栈顶元素: 3
字符串栈: Stack[Hello, World, Template]
学生信息: {Alice: 95}
数据点: {1: 3.14159}
智能指针值: 42
智能指针字符串: Smart Pointer
字符串长度: 13
模板特化
完整示例
#include <iostream>
#include <cstring>
// 通用模板
template <typename T>
class TypeInfo {
public:
static const char* name() { return "Unknown"; }
static int size() { return sizeof(T); }
};
// 全特化 - int类型
template <>
class TypeInfo<int> {
public:
static const char* name() { return "int"; }
static int size() { return sizeof(int); }
};
// 全特化 - double类型
template <>
class TypeInfo<double> {
public:
static const char* name() { return "double"; }
static int size() { return sizeof(double); }
};
// 偏特化 - 指针类型
template <typename T>
class TypeInfo<T*> {
public:
static const char* name() {
static std::string name = std::string("pointer to ") + TypeInfo<T>::name();
return name.c_str();
}
static int size() { return sizeof(T*); }
};
// 偏特化 - 数组类型
template <typename T, size_t N>
class TypeInfo<T[N]> {
public:
static const char* name() {
static std::string name = std::string("array[") + std::to_string(N) + "] of " + TypeInfo<T>::name();
return name.c_str();
}
static int size() { return N * sizeof(T); }
};
// 函数模板特化示例
template <typename T>
bool isEqual(T a, T b) {
return a == b;
}
// 函数模板特化 - 浮点数比较
template <>
bool isEqual<double>(double a, double b) {
return std::abs(a - b) < 1e-10;
}
void testTemplateSpecialization() {
std::cout << "\n=== 模板特化测试 ===" << std::endl;
// 测试类型信息
std::cout << "TypeInfo<int>: "
<< TypeInfo<int>::name()
<< ", Size: " << TypeInfo<int>::size() << std::endl;
std::cout << "TypeInfo<double>: "
<< TypeInfo<double>::name()
<< ", Size: " << TypeInfo<double>::size() << std::endl;
std::cout << "TypeInfo<int*>: "
<< TypeInfo<int*>::name()
<< ", Size: " << TypeInfo<int*>::size() << std::endl;
std::cout << "TypeInfo<int[5]>: "
<< TypeInfo<int[5]>::name()
<< ", Size: " << TypeInfo<int[5]>::size() << std::endl;
// 测试函数模板特化
std::cout << "\n浮点数比较测试:" << std::endl;
double d1 = 1.0 / 3.0;
double d2 = 0.3333333333333333;
double d3 = 0.34;
std::cout << "isEqual(1, 1) = " << isEqual(1, 1) << std::endl;
std::cout << "isEqual(1.0, 1.0) = " << isEqual(1.0, 1.0) << std::endl;
std::cout << "isEqual(d1, d2) = " << isEqual(d1, d2) << std::endl;
std::cout << "isEqual(d1, d3) = " << isEqual(d1, d3) << std::endl;
}
输出结果:
=== 模板特化测试 ===
TypeInfo<int>: int, Size: 4
TypeInfo<double>: double, Size: 8
TypeInfo<int*>: pointer to int, Size: 8
TypeInfo<int[5]>: array[5] of int, Size: 20
浮点数比较测试:
isEqual(1, 1) = 1
isEqual(1.0, 1.0) = 1
isEqual(d1, d2) = 1
isEqual(d1, d3) = 0
模板元编程
#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;
};
// 编译时判断素数
template <int N, int D = N - 1>
struct IsPrime {
static const bool value = (N % D != 0) && IsPrime<N, D - 1>::value;
};
template <int N>
struct IsPrime<N, 1> {
static const bool value = true;
};
template <int N>
struct IsPrime<N, 0> {
static const bool value = false;
};
// 编译时斐波那契数列
template <int N>
struct Fibonacci {
static const int value = Fibonacci<N - 1>::value + Fibonacci<N - 2>::value;
};
template <>
struct Fibonacci<0> {
static const int value = 0;
};
template <>
struct Fibonacci<1> {
static const int value = 1;
};
void testTemplateMetaprogramming() {
std::cout << "\n=== 模板元编程测试 ===" << std::endl;
std::cout << "编译时计算:" << std::endl;
std::cout << "Factorial<5>::value = " << Factorial<5>::value << std::endl;
std::cout << "Factorial<10>::value = " << Factorial<10>::value << std::endl;
std::cout << "\n编译时素数判断:" << std::endl;
std::cout << "IsPrime<2>::value = " << IsPrime<2>::value << std::endl;
std::cout << "IsPrime<13>::value = " << IsPrime<13>::value << std::endl;
std::cout << "IsPrime<15>::value = " << IsPrime<15>::value << std::endl;
std::cout << "IsPrime<97>::value = " << IsPrime<97>::value << std::endl;
std::cout << "\n斐波那契数列:" << std::endl;
std::cout << "Fibonacci<0>::value = " << Fibonacci<0>::value << std::endl;
std::cout << "Fibonacci<5>::value = " << Fibonacci<5>::value << std::endl;
std::cout << "Fibonacci<10>::value = " << Fibonacci<10>::value << std::endl;
}
输出结果:
=== 模板元编程测试 ===
编译时计算:
Factorial<5>::value = 120
Factorial<10>::value = 3628800
编译时素数判断:
IsPrime<2>::value = 1
IsPrime<13>::value = 1
IsPrime<15>::value = 0
IsPrime<97>::value = 1
斐波那契数列:
Fibonacci<0>::value = 0
Fibonacci<5>::value = 5
Fibonacci<10>::value = 55
可变参数模板
#include <iostream>
#include <string>
// 基本情况
void printAll() {
std::cout << std::endl;
}
// 可变参数模板
template <typename T, typename... Args>
void printAll(T first, Args... args) {
std::cout << first;
if (sizeof...(args) > 0) {
std::cout << ", ";
}
printAll(args...);
}
// 编译时计算参数个数
template <typename... Args>
struct CountArgs {
static const int value = sizeof...(Args);
};
// 求和模板
template <typename... Args>
auto sumAll(Args... args) {
return (args + ...); // C++17折叠表达式
}
// 构造任意类型元组
template <typename... Args>
void makeTuple(Args... args) {
std::cout << "Tuple with " << sizeof...(args) << " elements created" << std::endl;
}
void testVariadicTemplates() {
std::cout << "\n=== 可变参数模板测试 ===" << std::endl;
std::cout << "printAll测试:" << std::endl;
printAll(1, 2, 3, 4, 5);
printAll(1, 2.5, "hello", 'A', true);
std::cout << "\n参数计数测试:" << std::endl;
std::cout << "CountArgs<int, char, double>::value = "
<< CountArgs<int, char, double>::value << std::endl;
std::cout << "CountArgs<>::value = " << CountArgs<>::value << std::endl;
std::cout << "\n求和测试:" << std::endl;
std::cout << "sumAll(1, 2, 3, 4, 5) = " << sumAll(1, 2, 3, 4, 5) << std::endl;
std::cout << "sumAll(1.1, 2.2, 3.3) = " << sumAll(1.1, 2.2, 3.3) << std::endl;
std::cout << "\n元组测试:" << std::endl;
makeTuple(1, "test", 3.14, 'X');
}
输出结果:
=== 可变参数模板测试 ===
printAll测试:
1, 2, 3, 4, 5
1, 2.5, hello, A, 1
参数计数测试:
CountArgs<int, char, double>::value = 3
CountArgs<>::value = 0
求和测试:
sumAll(1, 2, 3, 4, 5) = 15
sumAll(1.1, 2.2, 3.3) = 6.6
元组测试:
Tuple with 4 elements created
注意事项
-
编译时代价:模板代码在编译时展开,可能导致编译时间增加
-
代码膨胀:每个不同类型的实例化都会生成独立的代码
-
错误信息:模板错误信息通常难以理解
-
分离编译:模板通常需要在头文件中实现
-
类型约束:C++20引入concept来改进类型约束
// C++20 Concepts示例
#include <concepts>
template <typename T>
concept Addable = requires(T a, T b) {
{ a + b } -> std::convertible_to<T>;
};
template <Addable T>
T add(T a, T b) {
return a + b;
}
综合测试程序
int main() {
testFunctionTemplates();
testClassTemplates();
testTemplateSpecialization();
testTemplateMetaprogramming();
testVariadicTemplates();
std::cout << "\n=== 所有测试完成 ===" << std::endl;
return 0;
}
总结
C++模板提供了强大的泛型编程能力:
-
函数模板:编写与类型无关的函数
-
类模板:创建通用的数据结构
-
模板特化:为特定类型提供优化实现
-
模板元编程:编译时计算和类型计算
-
可变参数模板:处理任意数量和类型的参数
模板是C++标准库(STL)的基石,熟练掌握模板编程是成为高级C++开发者的关键技能。