ITPub博客

首页 > 应用开发 > IT综合 > C++模板与泛型编程:类型安全的通用代码实践

C++模板与泛型编程:类型安全的通用代码实践

投稿 IT综合 作者:bhluo 时间:2026-01-26 15:15:40 0 删除 编辑

# 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/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2015-11-01

  • 博文量
    895
  • 访问量
    934084