模板特例化,偏特化,左右值引用

本文介绍了C++中模板特例化的概念与应用,包括模板类和模板函数的特例化方式,以及如何通过特例化处理特定类型的特殊情况。此外还讨论了非类型模板参数的应用场景。


前言

temlplate<class T, typename U …>
其中尖括号<>中的T、U为模板参数,可以用class也可以用typename(书中推荐用ypename)

如类模板:
template<typename T>
class example{ T a; };
当T为某种特定的类型时需要改变类的定义,处理此特殊情况需要特例化模板:
template<>
class example<double> { int a; };

模板特例化大致意思为:如果class template拥有一个以上的template参数,我们可以针对其中某个(或数个,但非全部)template参数进行特例化工作,换句话说,我们可以在泛化设计中提供一个特例化版本(也就是将泛化版本中的某些template参数赋予明确的指定)。

又如:
template<typename T>
class C { ... };         这个泛化版本允许T为任何类型

template<typename T>
class C<T*> {  ... };    这个特化版本仅适用于“T为原生指针”的情况
                         “T为原生指针”便是“T为任何类型”的更进一步的条件限制

非类型模板参数

template<unsigned N, unsigned M>
int compare(const char (&p1)[N], const char (&p2)[M])
{
    return strcmp(p1, p2);
}
compare("hi", "mon");
模板实例化:
int compare(const char (&p1)[3], const char (&p2)[4])

模板类特例化

模板函数特例化

template<class I, class T>
void func_impl(I iter, T)
{
    T a=9.5;
    cout << a << endl;
}
template<class I>
inline void func(I iter)
{
    func_impl(iter, *iter);
}
template<> //模板特例化
inline void func<int>(int iter)
{
    cout << iter << endl;
}

::半特例化

template<typename T>
void func(T a) {}
// 以下半特例化可单独写
template<typename T>
void func<T*>(T* a) {}

template<typename T>
void func(T* a) {}

左右值引用

这里涉及模板推导规则

template<typename T>
struct rm_ref
{
    typedef T type;
};
template<typename T>
struct rm_ref<T&&>
{
    typedef T type;
};
template<typename T>
struct rm_ref<T&>
{
    typedef T type;
};

template<typename _Tp>
    [[__nodiscard__]]
constexpr typename rm_ref<_Tp>::type&&
convert2rvalue(_Tp&& __t) noexcept
{
    return static_cast<typename rm_ref<_Tp>::type&&>(__t); 
}

rm_ref为去除引用获得去除引用后的类型
当rm_ref<?>中的?为 int时,T被推导为int;
当?为int&时匹配特例化struct rm_ref<T&>,T被推导为int;
当?为int&&时,匹配rm_ref<T&&>,T被推导为int;
template<typename T> void fun(T&& a)为万能引用,当参数为右值时自不必多说;当参数为int&时,似是fun(int& &a),a为引用类型,引向int&类型,T为int型。


总结

<think>好的,用户想了解C++模板类的实例方法。根据之前的对话,用户之前询问过线程安全的拷贝构造函数,现在转向模板类的实例。需要结合用户提供的引用内容,特别是引用1到3,来组织回答。 首先,用户的引用1提到了隐式实例和显式实例两种方法。引用2和3分别给出了类模板继承和实例的例子。需要确保覆盖这两种实例方法,并给出代码示例。 用户的问题是关于模板类实例的方法,所以需要分点解释隐式和显式实例,可能还要提到部分特例或完全特例。要注意使用用户提供的引用中的例子,比如引用2中的Base和Derived类,引用3中的array<int>的例子。 同时,用户之前的回答中提到了线程安全,但这次问题不涉及,所以不需要涉及多线程内容。需要保持回答结构清晰,符合用户要求的系统指令,比如行内公式用$符号,独立公式用$$,正确使用LaTeX语法,中文回答,生成相关问题等。 需要检查是否有遗漏的实例方法,比如显式实例的语法、何时使用显式实例,以及可能出现的常见问题和注意事项,比如模板定义可见性、重复实例错误等。另外,用户提供的引用中有关于派生类模板的例子,可能需要提到继承时的实例注意事项。 最后,生成的相关问题需要与模板实例相关,比如隐式和显式的区别、特例的应用场景、解决链接错误的方法等。确保引用标识正确,比如引用[^1][^2][^3]来自用户提供的资料。</think>以下是对C++模板类实例方法的系统说明,结合模板实例的核心机制与工程实践: --- ### 一、模板类实例基本原理 模板类实例是将通用模板转换为具体类型类的过程,其核心是**二次编译机制**: 1. 首次编译:检查模板语法(不生成机器码) 2. 实例编译:根据具体类型生成二进制代码 例如: ```cpp template<typename T> class Vector { // 模板定义 private: T* elements; int size; public: void push_back(const T& item); }; Vector<int> v1; // 实例int版本 Vector<double> v2; // 实例double版本 ``` 此时编译器会生成`Vector<int>`和`Vector<double>`两个独立类[^3] --- ### 二、实例方法分类 #### 1. 隐式实例(Implicit Instantiation) 通过对象声明自动触发,是最常用方式: ```cpp template<typename T> class Matrix { public: Matrix(int rows, int cols) : data(new T[rows*cols]) {} private: T* data; }; Matrix<float> m(3, 4); // 隐式实例float版本[^1] ``` 特性: - 按需生成代码(未使用的成员函数不实例) - 可能导致编译时间膨胀(多次相同类型实例) - 必须可见模板完整定义(头文件中定义) #### 2. 显式实例(Explicit Instantiation) 手动指定实例类型,控制代码生成: ```cpp // 模板声明 template<typename T> class CircularBuffer; // 显式实例指令 template class CircularBuffer<double>; // 生成double版本[^2] // 使用时不触发编译期生成 CircularBuffer<double> buf; // 直接使用预生成代码 ``` 优势: - 减少编译时间(避免重复实例) - 控制符号可见性(DLL/SO开发常用) - 强制检查模板有效性(提前发现错误) #### 3. 特实例(Specialization) ##### (1) 完全特(Full Specialization) ```cpp template<> class Vector<bool> { // 针对bool类型的特版本 private: uint8_t* packed_data; // 使用位压缩存储 public: void flip_all() { /* 位操作实现 */ } }; ``` ##### (2) 部分特Partial Specialization) ```cpp template<typename T> class Vector<T*> { // 针对指针类型的特 public: void clear() { for(int i=0; i<size; ++i) delete elements[i]; // 深度释放指针 } }; ``` --- ### 三、实例控制技巧 #### 1. 延迟实例(Lazy Instantiation) ```cpp template<typename T> class Logger { public: void log(const T& msg) { static_assert(std::is_copy_constructible_v<T>, // 仅在调用时检查 "T must be copy constructible"); // ... } }; Logger<std::thread> logger; // 合法(未调用log方法时不实例) ``` #### 2. 显式抑制实例 ```cpp extern template class Matrix<std::string>; // 声明但不实例[^1] ``` #### 3. 继承链中的实例 ```cpp template<typename T> class Base { public: virtual void serialize(T) const; }; template<typename T> class Derived : public Base<T> { // 派生类模板 public: void serialize(T) const override; }; // 显式实例基类会触发派生类实例 template class Base<int>; // 同时生成Derived<int>[^2] ``` --- ### 四、工程实践要点 1. **分离编译问题** 模板定义必须放在头文件中(或使用显式实例) 2. **符号重复解决方案** ```cpp // 在头文件中声明 extern template class Stack<double>; // 在.cpp文件中定义 template class Stack<double>; ``` 3. **类型推导辅助** ```cpp template<typename T=int> // 默认类型参数 class Buffer { /*...*/ }; Buffer<> buf; // 自动实例为Buffer<int> ``` 4. **C++17特性`if constexpr`** ```cpp template<typename T> class SmartPtr { public: void reset() { if constexpr(std::is_array_v<T>) { delete[] ptr; // 仅对数组类型生效 } else { delete ptr; } } }; ``` --- ### 五、调试与优 1. 查看实例结果(GCC): ```bash g++ -fdump-class-hierarchy -c template_use.cpp ``` 2. 减少编译时间: - 使用显式实例集中管理 - 预编译头文件(PCH) - 外部模板声明(C++11) 3. 检测未实例错误: ```cpp static_assert(sizeof(MyTemplate<char>) > 0, "Template instantiation failed"); ``` ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值