目录

C深入理解C模板从原理到实践

【C++】深入理解C++模板:从原理到实践

引言

C++模板是泛型编程的核心工具,它允许开发者编写与类型无关的代码。然而,模板的实现机制和编译过程往往令人感到神秘。本文将通过模板 实例化过程类型推导规则模板元编程 三个维度,深入理解C++模板的工作原理。

1、模板基础知识

1.1 函数模板

template <class T>
void Swap(T& a, T& b) {
    T temp = a;
    a = b;
    b = temp;
}
  • 编译器通过调用上下文推导 T 的类型。
  • 生产具体类型版本的过程成为 隐式实例化
template <class T>
void Swap(T& a, T& b) {
    T temp = a;
    a = b;
    b = temp;
}

int main() {
    int a = 1, b = 2;
    std::cout << a << " " << b << std::endl;
    Swap(a, b);
    std::cout << a << " " << b << std::endl;
    std::cout << "---------" << std::endl;

    double c = 1.2, d = 3.4;
    std::cout << c << " " << d << std::endl;
    Swap(c, d);
    std::cout << c << " " << d << std::endl;
    return 0;
}

https://i-blog.csdnimg.cn/img_convert/9b644e7f3a0be966dff3a8baa696dd4f.png

https://i-blog.csdnimg.cn/img_convert/68ee2a45e707053e7d60f8ccf3d5d07b.png

1.2 类模板

template <class T>
class Vector {
public:
    Vector(int n = 5)
        : size_(0), capacity_(n)
    {
        data_ = new T[n];
    }

    void PushBack(const T& item) {
        // 尾插逻辑...
    }

    ~Vector() {
        delete[] data_;
        size_ = capacity_ = 0;
    }
private:
    T* data_;
    int size_;
    int capacity_;
};
  • 必须显式指定模板参数类型(C++17前)。
  • 支持成员函数模板和静态成员。
template <typename T>
class Vector {
public:
    Vector(int n = 5)
        : size_(0), capacity_(n)
    {
        data_ = new T[n];
    }

    void PushBack(const T& item) {
        // 尾插逻辑...
    }

    ~Vector() {
        delete[] data_;
        size_ = capacity_ = 0;
    }
private:
    T* data_;
    int size_;
    int capacity_;
};

int main() {
    Vector<int> v;
    return 0;
}

typename 是用来定义模板参数的关键字,也可以使用 class

2、模板实例化机制

2.1 两阶段编译

  1. 模板定义阶段:检查语法和与模板参数无关的错误。
  2. 实例化阶段:生产具体类型的代码,检查类型相关操作。

https://i-blog.csdnimg.cn/img_convert/bf51eff837eccfc98cb437d34294fb63.png

2.2 实例化控制

  • 显示实例化(减少代码膨胀)。
template <class T>
void Swap(T& a, T& b) {
    T temp = a;
    a = b;
    b = temp;
}


template <class T>
class Vector {
public:
    Vector(int n = 5)
        : size_(0), capacity_(n)
    {
        data_ = new T[n];
    }

    void PushBack(const T& item) {
        // 尾插逻辑...
    }

    ~Vector() {
        delete[] data_;
        size_ = capacity_ = 0;
    }
private:
    T* data_;
    int size_;
    int capacity_;
};

template class Vector<int>; // 显示实例化整个类
template void Swap<int>(int&, int&); // 显示实例化函数
  • 外部实例化声明(C++11)。
extern template class Vector<int>;

3、模板参数推导

3.1 类型推导规则

  • 函数模板参数推导遵循以下优先级:
    1. 完美匹配。

    2. 类型提升( float

      → \rightarrow

      double )。

    3. 标准转换( int

      → \rightarrow

      long )。

    4. 用户定义转换。

3.2 CTAD(类模板参数推导)

  • C++17引入的自动推导机制。
std::vector v{1,2,3}; // 推导为std::vector<int>

4、模板特化与偏特化

4.1 全特化

template <>
class ClassName<void*> {
    //针对void*类型的特殊实现
};

4.2 偏特化

template <class T>
class ClassName<T*> {
    //针对所有指针类型的通用实现
};

5、模板元编程

5.1 编译时计算

template <int N>
struct Factorial {
    static const int ret = N * Factorial<N - 1>::ret;
};

template <>
struct Factorial<0> {
    static const int ret = 1;
};

int main() {
    std::cout << Factorial<5>::ret << std::endl; // 120
    return 0;
}

5.2 SFINAE与类型检查

template <class T>
class std::enable_if<std::is_integral<T>::value>::type process(T val) {
    // 仅对整数类型生效的实现
}

5.3 C++20概念(Concepts)

template <class T>
requires std::floating_point<T>
T precise_calc(T a, T b) {
    // 高精度浮点计算
}

6、模板实践建议

  1. 避免过度使用模板元编程(TMP)。
  2. 使用 static_assert 进行模板参数校验。
  3. 注意模板导致的代码膨胀问题。
  4. 有限选择标准库类型特征(type_traits)