C++模板进阶1.0
·
目录
类型模板参数(Type Template Parameter)
非类型模板参数(Non-type Template Parameter)
二,模板特化和偏特化(Specialization and partial specialization)
1.核心概念与区别(Core concepts and differences)
3.偏特化 (Partial Specialization)
一,模板参数列表
-
类型模板参数(Type Template Parameter)
class T或typename T表示T是一个类型占位符,在实例化时会被具体类型(如int、string)替换。- 使用
class或typename在此处等价,但typename更通用(尤其在嵌套依赖类型中)。
-
非类型模板参数(Non-type Template Parameter)
size_t N = 10表示N是一个编译期常量值,类型为size_t(通常是整数类型),默认值为10。- 非类型参数必须是整数、枚举、指针或引用等可在编译期确定的值。
- 代表array(array相对于数组越界检查严格,数组是抽查啊,功能和数组一样)
template<class T, size_t N = 10>//c++20之前可以size_t(不可以其他的), //但是在c++20就可以其他的了 class array { public: T& operator[](const size_t x) { assert(x < N); return a[x]; } private: T a[N]; };
二,模板特化和偏特化(Specialization and partial specialization)
在 C++ 中,模板特化(Specialization) 和 偏特化(Partial Specialization) 是泛型编程的核心技术,用于为特定类型或类型模式提供定制化实现。以下是深度解析:
1.核心概念与区别(Core concepts and differences)
| 特性 | 全特化 (Full Specialization) | 偏特化 (Partial Specialization) |
|---|---|---|
| 定义 | 为所有模板参数指定具体类型的完全定制实现 | 仅对部分参数特化,保留其他参数的泛型特性 |
| 适用对象 | 类模板、函数模板 | 仅类模板(函数模板不支持偏特化) |
| 语法 | template<> class MyClass<int> {...} |
template<class T> class MyClass<T*> {...} |
| 匹配优先级 | 最高优先级 | 次高于通用模板但低于全特化 |
2.模板特化(Specialization)
跟函数重载差不多,有现成的先调用现成的,没有再找匹配的,最后就是模板。
template<class T>
class A
{
public:
A()
{
std::cout << "class A" << std::endl;
}
private:
T a1;
};
template<>
class A<int>
{
public:
A()
{
std::cout << "class A<int>" << std::endl;
}
};
template<>
class A<int*>
{
public:
A()//如果要传参推荐( int* const &x)
{
std::cout << "class A<int*>" << std::endl;
}
};
int main()
{
A<char> b;//class A
A<int> a;//class A<int>
A<int*> d;//class A<int*>
return 0;
}
3.偏特化 (Partial Specialization)
这个主要是指针和引用(泛型)
template<class T, class T1>
class B
{
public:
B()
{
std::cout << "class B" << std::endl;
}
};
template<class T, class T1>
class B<T*,T1*>
{
public:
B()//如果要传参推荐( T* const &x1,T1* const &x1)
{
std::cout << "class B<T*,T1*>" << std::endl;
}
};
template<class T, class T1>
class B<T&, T1&>
{
public:
B()
{
std::cout << "class B<T&, T1&>" << std::endl;
}
};
int main()
{
pz::B<int, int> x;//class B
pz::B<int*, int*>y;//class B<T*, T1*>
pz::B<int&, int&>z;//class B<T&, T1&>
return 0;
}
三,声明和定义分离
1.核心挑战:模板的编译模型
- 根本问题:模板是编译期生成的代码蓝图,编译器必须在实例化时看到完整定义
- 传统分离后果:将定义放在
.cpp文件会导致链接器报undefined reference - 根本原因:模板实例化发生在调用点,若定义不可见则无法生成机器码

2.解决方案
方案 1:显式实例化(Explicit Instantiation)
适用场景:已知模板会被哪些类型使用
// myarray.h(声明)
template<typename T>
class MyArray
{
public: void add(T item); // 仅声明 }
;
// myarray.cpp(定义 + 显式实例化)
template<typename T>
void MyArray<T>::add(T item)
{ /* 实现 */ } // 显式实例化所需类型(编译器在此生成代码)
template class MyArray<int>; // 生成 int 版本
template class MyArray<double>; // 生成 double 版本
优点:
- 实现真正分离(.h 纯声明,.cpp 含定义)
- 控制编译产物体积(仅实例化指定类型)
缺点:
- 不支持未知类型(如用户自定义类)
- 维护成本高(需预判所有使用类型)
方案 2:.ipp / .tpp 包含法
适用场景:保持头文件简洁性
// myarray.h
template<typename T>
class MyArray
{
public:
void add(T item);
}; // 包含定义文件(注意顺序!)
#include "myarray.ipp" // 在类声明后立即包含
// myarray.ipp(实现)
template<typename T>
void MyArray<T>::add(T item)
{
// 实现细节
}
关键细节:
- 使用
.ipp/.tpp扩展名区分模板实现文件 - 头文件末尾包含实现(确保类声明先被解析)
- 编译时视为同一翻译单元(解决实例化问题)
更多推荐

所有评论(0)