首页 > 应用开发 > IT综合 > C++模板与泛型编程:类型安全的通用代码实践
# C++模板与泛型编程:类型安全的通用代码实践
## 模板编程基础与原理
C++模板是实现泛型编程的核心机制,允许编写独立于具体类型的通用代码。模板在编译时进行实例化,生成针对特定类型的代码版本,从而实现类型安全的重用。
```cpp
// 基础函数模板
template<typename T>
T max(T a, T b) {
return (a > b) ? a : b;
}
// 使用显式模板参数
auto result1 = max<int>(10, 20); // 显式指定int
auto result2 = max(3.14, 2.71); // 自动推导为double
// 多类型参数模板
template<typename T1, typename T2>
auto add(T1 a, T2 b) -> decltype(a + b) {
return a + b;
}
// 使用示例
auto sum1 = add(10, 3.14); // int + double → double
auto sum2 = add(string("Hello"), " World"); // string + const char*
```
## 类模板设计与实现
### 基础类模板
```cpp
// 简单的栈类模板
template<typename T, size_t Capacity = 100>
class Stack {
private:
T data[Capacity];
size_t top;
public:
Stack() : top(0) {}
// 压栈
void push(const T& value) {
if (top >= Capacity) {
throw std::overflow_error("栈已满");
}
data[top++] = value;
}
// 出栈
T pop() {
if (top == 0) {
throw std::underflow_error("栈为空");
}
return data[--top];
}
// 查看栈顶
const T& peek() const {
if (top == 0) {
throw std::underflow_error("栈为空");
}
return data[top - 1];
}
bool empty() const { return top == 0; }
size_t size() const { return top; }
size_t capacity() const { return Capacity; }
};
// 使用示例
void stack_demo() {
Stack<int> int_stack;
int_stack.push(10);
int_stack.push(20);
std::cout << "栈顶: " << int_stack.peek() << std::endl;
Stack<std::string, 50> string_stack;
string_stack.push("Hello");
string_stack.push("World");
}
// 模板特化:针对特定类型的优化实现
template<>
class Stack<bool, 100> {
private:
std::bitset<100> data; // 使用bitset优化布尔值存储
size_t top;
public:
Stack() : top(0) {}
void push(bool value) {
if (top >= 100) throw std::overflow_error("栈已满");
data[top++] = value;
}
bool pop() {
if (top == 0) throw std::underflow_error("栈为空");
return data[--top];
}
// 其他方法...
};
```
### 模板元编程基础
```cpp
// 编译时计算:斐波那契数列
template<size_t N>
struct Fibonacci {
static constexpr size_t value =
Fibonacci<N-1>::value + Fibonacci<N-2>::value;
};
template<>
struct Fibonacci<0> {
static constexpr size_t value = 0;
};
template<>
struct Fibonacci<1> {
static constexpr size_t value = 1;
};
// 使用示例
constexpr auto fib10 = Fibonacci<10>::value; // 编译时计算55
// 类型萃取:检查类型特性
template<typename T>
struct IsPointer {
static constexpr bool value = false;
};
template<typename T>
struct IsPointer<T*> {
static constexpr bool value = true;
};
template<typename T>
inline constexpr bool IsPointer_v = IsPointer<T>::value;
// 使用
static_assert(IsPointer_v<int*> == true, "int*应该是指针类型");
static_assert(IsPointer_v<int> == false, "int不是指针类型");
```
## 高级模板特性
### 可变参数模板
```cpp
// 可变参数模板:参数包展开
template<typename... Args>
void printAll(Args... args) {
// C++17折叠表达式
(std::cout << ... << args) << std::endl;
}
// 递归展开版本(C++11/14)
template<typename T>
void print(T t) {
std::cout << t << std::endl;
}
template<typename T, typename... Args>
void print(T first, Args... rest) {
std::cout << first << " ";
print(rest...); // 递归展开
}
// 完美转发示例
template<typename... Args>
auto make_vector(Args&&... args)
-> std::vector<std::common_type_t<Args...>> {
std::vector<std::common_type_t<Args...>> result;
result.reserve(sizeof...(args));
// 使用初始化列表和折叠表达式
(result.push_back(std::forward<Args>(args)), ...);
return result;
}
// 使用示例
auto vec = make_vector(1, 2, 3, 4, 5);
// 参数包长度计算
template<typename... Args>
constexpr size_t countArgs(Args...) {
return sizeof...(Args);
}
// 编译时参数包处理
template<typename... Ts>
struct TypeList {
static constexpr size_t size = sizeof...(Ts);
};
// 类型提取
template<size_t N, typename... Ts>
struct GetType;
template<size_t N, typename T, typename... Ts>
struct GetType<N, T, Ts...> {
using type = typename GetType<N-1, Ts...>::type;
};
template<typename T, typename... Ts>
struct GetType<0, T, Ts...> {
using type = T;
};
// 使用
using MyTypes = TypeList<int, double, std::string>;
static_assert(MyTypes::size == 3, "应该有3个类型");
using SecondType = GetType<1, int, double, std::string>::type; // double
```
### 概念约束(C++20)
```cpp
#if __cplusplus >= 202002L
#include <concepts>
#include <type_traits>
// 定义概念
template<typename T>
concept Arithmetic = requires(T a, T b) {
{ a + b } -> std::convertible_to<T>;
{ a - b } -> std::convertible_to<T>;
{ a * b } -> std::convertible_to<T>;
{ a / b } -> std::convertible_to<T>;
{ -a } -> std::convertible_to<T>;
};
template<typename T>
concept Printable = requires(std::ostream& os, T val) {
{ os << val } -> std::convertible_to<std::ostream&>;
};
// 使用概念约束的模板
template<Arithmetic T>
T square(T x) {
return x * x;
}
template<Printable T>
void print_squared(T x) {
std::cout << square(x) << std::endl;
}
// 组合概念
template<typename T>
concept PrintableArithmetic = Arithmetic<T> && Printable<T>;
template<PrintableArithmetic T>
void process_value(T x) {
std::cout << "值: " << x << ", 平方: " << square(x) << std::endl;
}
// requires子句
template<typename T>
requires std::is_copy_constructible_v<T> && std::is_copy_assignable_v<T>
class SafeContainer {
// 需要可拷贝构造和可拷贝赋值的类型
};
#endif // C++20
```
## 类型安全的通用容器
```cpp
// 类型安全的数组视图
template<typename T>
class ArrayView {
private:
T* data_;
size_t size_;
public:
// 构造函数
template<size_t N>
ArrayView(T (&array)[N]) : data_(array), size_(N) {}
ArrayView(std::vector<T>& vec)
: data_(vec.data()), size_(vec.size()) {}
ArrayView(T* data, size_t size)
: data_(data), size_(size) {}
// 访问元素(带边界检查)
T& operator[](size_t index) {
if (index >= size_) {
throw std::out_of_range("数组越界");
}
return data_[index];
}
const T& operator[](size_t index) const {
if (index >= size_) {
throw std::out_of_range("数组越界");
}
return data_[index];
}
// 迭代器支持
T* begin() { return data_; }
T* end() { return data_ + size_; }
const T* begin() const { return data_; }
const T* end() const { return data_ + size_; }
size_t size() const { return size_; }
bool empty() const { return size_ == 0; }
// 子视图
ArrayView subview(size_t offset, size_t count) const {
if (offset + count > size_) {
throw std::out_of_range("子视图超出范围");
}
return ArrayView(data_ + offset, count);
}
};
// 使用示例
void array_view_demo() {
int arr[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
ArrayView<int> view(arr);
// 安全访问
for (size_t i = 0; i < view.size(); ++i) {
view[i] = i * i;
}
// 范围for循环
for (int val : view) {
std::cout << val << " ";
}
std::cout << std::endl;
// 子视图
auto sub = view.subview(3, 4);
for (int val : sub) {
std::cout << val << " ";
}
}
```
## 策略模式与模板
```cpp
// 排序策略模板
template<typename T, typename Compare = std::less<T>>
class Sorter {
private:
Compare comp_;
public:
// 默认使用std::less
Sorter() = default;
// 可以指定自定义比较器
explicit Sorter(Compare comp) : comp_(comp) {}
// 冒泡排序实现
void bubble_sort(std::vector<T>& arr) {
for (size_t i = 0; i < arr.size(); ++i) {
for (size_t j = 0; j < arr.size() - i - 1; ++j) {
if (comp_(arr[j + 1], arr[j])) {
std::swap(arr[j], arr[j + 1]);
}
}
}
}
// 选择排序实现
void selection_sort(std::vector<T>& arr) {
<"kb.csxthr.com"><"lb.zhaiLimao.com"><"mb.yunruiwater.cn">
for (size_t i = 0; i < arr.size(); ++i) {
size_t min_idx = i;
for (size_t j = i + 1; j < arr.size(); ++j) {
if (comp_(arr[j], arr[min_idx])) {
min_idx = j;
}
}
std::swap(arr[i], arr[min_idx]);
}
}
};
// 使用示例
void sorting_demo() {
std::vector<int> numbers = {5, 2, 8, 1, 9, 3};
// 默认升序排序
Sorter<int> default_sorter;
default_sorter.bubble_sort(numbers);
// 降序排序
Sorter<int, std::greater<int>> descending_sorter;
descending_sorter.selection_sort(numbers);
// 自定义比较器
struct CaseInsensitiveCompare {
bool operator()(const std::string& a, const std::string& b) const {
return std::lexicographical_compare(
a.begin(), a.end(),
b.begin(), b.end(),
[](char c1, char c2) {
return std::tolower(c1) < std::tolower(c2);
});
}
};
std::vector<std::string> words = {"Apple", "banana", "Cherry"};
Sorter<std::string, CaseInsensitiveCompare> case_insensitive_sorter;
case_insensitive_sorter.bubble_sort(words);
}
// CRTP:奇异递归模板模式
template<typename Derived>
class EqualityComparable {
public:
bool operator!=(const Derived& other) const {
return !(static_cast<const Derived&>(*this) == other);
}
};
class Point : public EqualityComparable<Point> {
private:
int x, y;
public:
Point(int x, int y) : x(x), y(y) {}
// 只需要实现==操作符
bool operator==(const Point& other) const {
return x == other.x && y == other.y;
}
// 自动获得!=操作符
};
// 使用CRTP实现静态多态
template<typename Derived>
class Shape {
public:
double area() const {
return static_cast<const Derived*>(this)->area_impl();
}
void draw() const {
static_cast<const Derived*>(this)->draw_impl();
}
};
class Circle : public Shape<Circle> {
private:
double radius;
public:
explicit Circle(double r) : radius(r) {}
double area_impl() const {
return 3.14159 * radius * radius;
}
void draw_impl() const {
std::cout << "绘制圆形,半径: " << radius << std::endl;
}
};
class Square : public Shape<Square> {
private:
double side;
public:
explicit Square(double s) : side(s) {}
double area_impl() const {
return side * side;
}
void draw_impl() const {
std::cout << "绘制正方形,边长: " << side << std::endl;
}
};
// 使用
void shape_demo() {
Circle circle(5.0);
Square square(4.0);
std::cout << "圆形面积: " << circle.area() << std::endl;
std::cout << "正方形面积: " << square.area() << std::endl;
circle.draw();
square.draw();
}
```
## 类型擦除与std::any/function
```cpp
// 使用类型擦除实现通用回调
#include <functional>
#include <any>
#include <memory>
// 方法1:使用std::function
class EventDispatcher {
private:
using Handler = std::function<void()>;
std::vector<Handler> handlers;
public:
template<typename Callable>
void register_handler(Callable&& func) {
handlers.emplace_back(std::forward<Callable>(func));
}
void trigger_all() {
for (auto& handler : handlers) {
handler();
}
}
};
// 方法2:使用std::any存储任意类型
class AnyStorage {
private:
std::any data_;
public:
template<typename T>
AnyStorage(T&& value) : data_(std::forward<T>(value)) {}
template<typename T>
T* get() {
return std::any_cast<T>(&data_);
}
template<typename T>
const T* get() const {
return std::any_cast<T>(&data_);
}
template<typename T>
bool holds_type() const {
return data_.type() == typeid(T);
}
};
// 方法3:使用类型擦除模式
class Drawable {
public:
virtual ~Drawable() = default;
virtual void draw() const = 0;
virtual std::unique_ptr<Drawable> clone() const = 0;
};
template<typename T>
class DrawableModel : public Drawable {
private:
T object;
public:
explicit DrawableModel(T obj) : object(std::move(obj)) {}
void draw() const override {
object.draw(); // 假设T有draw方法
}
std::unique_ptr<Drawable> clone() const override {
return std::make_unique<DrawableModel<T>>(object);
}
};
class Drawing {
private:
std::vector<std::unique_ptr<Drawable>> shapes;
public:
template<typename T>
void add_shape(T shape) {
shapes.push_back(std::make_unique<DrawableModel<T>>(std::move(shape)));
<"nb.sxyicheng.cn"><"ob.jsnjz.cn"><"pb.csxthr.com">
}
void draw_all() const {
for (const auto& shape : shapes) {
shape->draw();
}
}
};
```
## 模板元编程实战
```cpp
// 编译时字符串处理
template<char... Chars>
struct FixedString {
static constexpr char value[] = {Chars..., '\0'};
static constexpr size_t length = sizeof...(Chars);
};
// 用户定义字面量(C++14)
template<typename CharT, CharT... Chars>
constexpr FixedString<Chars...> operator""_fs() {
return {};
}
// 编译时类型列表操作
template<typename... Ts>
struct TypeList {};
// 获取类型列表长度
template<typename List>
struct Length;
template<typename... Ts>
struct Length<TypeList<Ts...>> {
static constexpr size_t value = sizeof...(Ts);
};
// 类型列表连接
template<typename List1, typename List2>
struct Concat;
template<typename... Ts1, typename... Ts2>
struct Concat<TypeList<Ts1...>, TypeList<Ts2...>> {
using type = TypeList<Ts1..., Ts2...>;
};
// 类型列表反转
template<typename List>
struct Reverse;
template<>
struct Reverse<TypeList<>> {
using type = TypeList<>;
};
template<typename T, typename... Ts>
struct Reverse<TypeList<T, Ts...>> {
using type = typename Concat<
typename Reverse<TypeList<Ts...>>::type,
TypeList<T>
>::type;
};
// 使用示例
using MyTypes = TypeList<int, double, std::string>;
using Reversed = Reverse<MyTypes>::type; // TypeList<std::string, double, int>
// SFINAE:替换失败不是错误
template<typename T, typename = void>
struct HasSizeMethod : std::false_type {};
template<typename T>
struct HasSizeMethod<T, std::void_t<decltype(std::declval<T>().size())>>
: std::true_type {};
template<typename T>
inline constexpr bool HasSizeMethod_v = HasSizeMethod<T>::value;
// 根据类型特性选择不同实现
template<typename Container>
auto get_size(const Container& c) {
if constexpr (HasSizeMethod_v<Container>) {
return c.size();
} else {
return c.length(); // 假设有length()方法
}
}
```
## 性能优化与最佳实践
```cpp
// 模板代码优化技巧
class TemplateOptimizations {
public:
// 1. 使用内联减少代码膨胀
template<typename T>
static inline T min(T a, T b) {
return (a < b) ? a : b;
}
// 2. 使用空基类优化(EBO)
template<typename T>
class OptimizedContainer : private T { // 继承而不是包含
// 如果T是空类,不会占用额外空间
};
// 3. 使用类型别名提高可读性
template<typename Key, typename Value>
using Map = std::unordered_map<Key, Value>;
// 4. 避免不必要的模板实例化
template<typename T>
void process_impl(T&& value) {
// 实际实现
}
// 非模板接口,减少实例化
void process(int value) { process_impl(value); }
void process(double value) { process_impl(value); }
void process(const std::string& value) { process_impl(value); }
// 5. 使用自动推导类型(C++14/17)
template<typename Container>
auto process_container(Container&& c) {
using ValueType = std::decay_t<decltype(*c.begin())>;
// 使用decltype(auto)保留引用性
decltype(auto) first = *c.begin();
return std::vector<ValueType>{c.begin(), c.end()};
}
};
// 模板代码调试技巧
#ifdef DEBUG_TEMPLATES
template<typename T>
void debug_type() {
std::cout << "类型: " << typeid(T).name() << std::endl;
std::cout << "大小: " << sizeof(T) << " 字节" << std::endl;
std::cout << "对齐: " << alignof(T) << " 字节" << std::endl;
}
#endif
// 静态断言提供编译时检查
template<typename T>
class Container {
static_assert(std::is_default_constructible_v<T>,
"T必须可默认构造");
static_assert(std::is_copy_constructible_v<T> ||
std::is_move_constructible_v<T>,
"T必须可拷贝或移动构造");
// 实现...
};
```
C++模板与泛型编程提供了强大的类型抽象能力,使得可以编写出既通用又类型安全的代码。从基础的函数模板到高级的模板元编程,从类型约束到可变参数模板,这些技术共同构成了现代C++泛型编程的基础。掌握模板编程不仅能够提高代码的重用性和类型安全性,还能在编译期完成更多工作,提升运行时性能。通过合理应用模板技术,可以构建出既灵活又高效的C++程序。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/19545/viewspace-3108960/ ,如需转载,请注明出处,否则将追究法律责任。