C++模板是泛型编程的核心,允许编写与类型无关的代码。通过模板,可以定义函数模板和类模板,支持多种数据类型的操作。例如:
template
T add(T a, T b) { return a + b; }
template
class Container {
T data;
// ... 成员函数
};
定义:为模板的所有参数提供特定类型的实现,覆盖通用模板的行为。
语法:
template<>
class/struct 模板名<具体类型列表> { ... };
示例:
template
class Printer {
public:
void print(const T& val) { std::cout << "通用版本: " << val << std::endl; }
};
// 完全特例化int版本
template<>
class Printer {
public:
void print(int val) { std::cout << "int特例化: " << val << std::endl; }
};
使用场景:当某个具体类型需要特殊处理时(如优化性能、避免通用实现的问题)。
定义:针对模板参数的部分组合或特性(如指针、引用、模板嵌套等)提供特化版本。
语法:
template<模板参数列表>
class/struct 模板名<特化的参数模式> { ... };
示例:
template
class Printer { // 部分特例化指针类型
public:
void print(T* ptr) { std::cout << "指针版本: " << *ptr << std::endl; }
};
// 部分特例化两个类型相同的场景
template
class Pair { ... };
template
class Pair { ... }; // 当两个类型相同时使用此版本
与完全特例化的区别:
T*
)。注意:函数模板不支持部分特例化,但可通过重载模拟类似行为。
概念:一种通过模板特例化获取类型信息或转换类型的技术,常用于编译期类型计算。
实现方式:通过完全特例化或部分特例化定义类型属性。
示例1:判断是否为指针
template
struct is_pointer {
static const bool value = false;
};
template
struct is_pointer { // 部分特例化指针类型
static const bool value = true;
};
// 使用
bool isIntPtr = is_pointer::value; // true
示例2:移除const修饰符
template
struct remove_const {
using type = T;
};
template
struct remove_const { // 部分特例化const T
using type = T;
};
// 使用
remove_const::type x = 5; // x的类型为int
应用场景:
std::iterator_traits
萃取迭代器的值类型、指针类型等。std::enable_if
实现SFINAE(替换失败不是错误)。std::is_integral
类型优化)。#include
// 类型萃取:判断是否为浮点类型
template
struct is_floating_point {
static const bool value = false;
};
template<>
struct is_floating_point {
static const bool value = true;
};
template<>
struct is_floating_point {
static const bool value = true;
};
// 根据类型选择打印策略
template::value>
class NumberPrinter;
// 浮点类型的特例化版本
template
class NumberPrinter {
public:
void print(T val) {
std::cout << "浮点数: " << val << std::endl;
}
};
// 非浮点类型的通用版本
template
class NumberPrinter {
public:
void print(T val) {
std::cout << "整数: " << val << std::endl;
}
};
int main() {
NumberPrinter().print(42); // 输出:整数: 42
NumberPrinter().print(3.14); // 输出:浮点数: 3.14
}
通过灵活使用这些技术,可以编写出高效、可维护的泛型代码,充分体现C++模板编程的强大能力。
定义:函数模板允许编写与类型无关的通用函数,支持多种参数类型。
template
T max(T a, T b) {
return (a > b) ? a : b;
}
// 使用
int x = max(3, 5); // T推导为int
double y = max(2.5, 3.14); // T推导为double
核心特性:
类型推导:编译器根据传入参数自动推导模板参数类型。
显式指定类型:可强制指定模板参数:
int z = max(3, 5.5); // T显式指定为double
作用:为特定类型提供专用实现。
template<>
const char* max(const char* a, const char* b) {
return (strcmp(a, b) > 0) ? a : b;
}
// 使用
const char* s = max("apple", "banana"); // 调用特例化版本
限制:
虽然不能部分特例化函数模板,但可以通过重载实现类似效果:
// 通用版本
template
void process(T val) {
std::cout << "通用类型处理\n";
}
// 重载指针版本(模拟部分特例化)
template
void process(T* ptr) {
std::cout << "指针类型处理\n";
}
// 使用
int x = 5;
process(x); // 调用通用版本
process(&x); // 调用指针重载版本
#include
template
void printValue(T val) {
if constexpr (std::is_pointer_v) { // C++17编译期条件判断
std::cout << "指针指向的值: " << *val << "\n";
} else {
std::cout << "普通值: " << val << "\n";
}
}
// 使用
int a = 10;
printValue(a); // 输出:普通值: 10
printValue(&a); // 输出:指针指向的值: 10
当多个重载版本匹配时,编译器优先级:
示例:
template
void log(T val) { std::cout << "通用模板\n"; }
template
void log(T* val) { std::cout << "指针模板\n"; } // 更具体的重载
void log(int val) { std::cout << "非模板int版本\n"; } // 非模板函数
// 使用
int x = 5;
log(x); // 调用非模板int版本
log(&x); // 调用指针模板
log(3.14); // 调用通用模板
enable_if
通过模板元编程控制函数模板的有效性:
#include
// 仅允许整数类型调用
template
typename std::enable_if_t, void>
handleNumber(T num) {
std::cout << "处理整数: " << num << "\n";
}
// 仅允许浮点类型调用
template
typename std::enable_if_t, void>
handleNumber(T num) {
std::cout << "处理浮点数: " << num << "\n";
}
// 使用
handleNumber(42); // 输出:处理整数: 42
handleNumber(3.14); // 输出:处理浮点数: 3.14
// handleNumber("test"); // 编译错误:无匹配函数
特性 | 函数模板 | 类模板 |
---|---|---|
特化方式 | 支持完全特例化 | 支持完全特例化和部分特例化 |
参数推导 | 支持自动类型推导(无需<> ) |
必须显式指定或通过构造函数推导(C++17起) |
重载 | 可直接重载 | 通过成员函数重载 |
部分特例化 | 不支持(通过重载模拟) | 支持 |
典型应用场景 | 通用算法(如排序、数学运算) | 容器(如vector )、工具类 |
#include
#include
#include
// 基础类型序列化
template
void serialize(T val) {
if constexpr (std::is_arithmetic_v) {
std::cout << "序列化数值: " << val << "\n";
} else {
static_assert(std::is_arithmetic_v, "仅支持基础类型!");
}
}
// 指针特化版本
template
void serialize(T* ptr) {
if (ptr != nullptr) {
std::cout << "序列化指针: ";
serialize(*ptr); // 递归调用基础版本
}
}
// 容器特化版本(需C++20概念支持,此处简化)
template
void serialize(const std::vector& vec) {
std::cout << "序列化容器[ ";
for (const auto& item : vec) {
serialize(item); // 递归调用
}
std::cout << "]\n";
}
// 使用
int main() {
serialize(42); // 基础类型
double d = 3.14;
serialize(&d); // 指针
std::vector vec = {1, 2, 3};
serialize(vec); // 容器
}
if constexpr
(C++17)可实现编译期条件分支,增强模板的泛用性。