模板特例化

模板特化(Template Specialization)

模板特化允许开发者为特定类型或类型组合提供专门的实现。当通用模板无法满足特定需求时,特化模板可以调整行为以处理特定的情况。C++ 支持全特化(Full Specialization)*******___***_偏特化(Partial Specialization),但需要注意的是,函数模板不支持偏特化,只能进行全特化

类模板的特例化

类模板全特化
template<typename T>  
class Printer {  
public:  
    void print(const T& obj) {  
        std::cout<<"General Printer "<<obj<<std::endl;  
    }  
};  
  
template<>  
class Printer<std::string> {  
public:  
    void print(const std::string& obj) {  
        std::cout<<"String Printer "<<obj<<std::endl;  
    }  
};
类模板偏特化
template<class T, class U>  
class Pair {  
public:  
    T first;  
    U second;  
    void print_pair() {  
        std::cout<<first<<" "<<second<<std::endl;  
    }  
};
template<typename T, typename U>  
class Pair<T, U*> {  
public:  
    T first;  
    U* second;  
    void print() {  
        std::cout<<first<<" "<<*second<<std::endl;  
    }  
};

调用实例

double temp = 1.1;  
Pair<int, double*> pair(20, &temp);  
pair.print();

编译器会优先匹配特例化的模板,再匹配普通模板,如果这里没有实现这个特例化,传指针会打印这个指针指向的地址。

函数模板的特例化

与类模板不同,函数模板不支持偏特化,只能进行全特化。当对函数模板进行全特化时,需要显式指定类型。
代码实例

template<typename T>  
void printValue(const T& obj) {  
    std::cout<<"General Printer "<<obj<<std::endl;  
}  
  
template<>  
inline void printValue<std::string>(const std::string& value) {  
    std::cout<<"String Printer "<<value<<std::endl;  
}  
  
template<>  
inline void printValue<int*>(int* const& value) {  
    std::cout<<"int* Printer "<<*value<<std::endl;  
}
需要注意的问题

一、 这里不加inline会报错重定义
在 C++ 中,模板(包括特化模板)的实现代码如果直接写在头文件(.h)中,且该头文件被多个 .cpp 文件包含,会导致编译器在每个 .cpp 中都生成一份函数定义,最终链接时出现 “重复定义” 冲突。

解决方案

  1. 将特化函数标记为 inline

    在函数前加 inline,强制编译器合并重复定义:

    template<>
    inline void printValue<std::string>(const std::string& value) {
        std::cout << "String Printer " << value << std::endl;
    }
    
  2. 将特化实现放在 .cpp 文件中

    头文件中仅声明特化,实现写在对应的 .cpp(如 template.cpp)中:

    // 头文件 template.h
    template<> void printValue<std::string>(const std::string& value);
    
    // 实现文件 template.cpp
    #include "template.h"
    template<>
    void printValue<std::string>(const std::string& value) {
        std::cout << "String Printer " << value << std::endl;
    }
    

二、为什么写int* const&
模板原声明是 void printValue(const T& obj),当 T=int* 时:

const T& 等价于 int* const&(“指向 int 的指针的常量引用”),而非 const int*&(“指向常量 int 的指针的引用”)。

如果你的实际需求是接收 “指向常量 int 的指针”,则应将特化的 T 定义为 const int*,此时 const T& 等价于 const int* const&,特化代码如下:

// 特化 T=const int*
template<>
inline void printValue<const int*>(const int* const& value) {
    std::cout << "const int* Printer " << *value << std::endl;
}

变参模板(Variadic Templates)

变参模板允许模板接受可变数量的参数,提供极高的灵活性,是实现诸如 std::tuplestd::variant 等模板库组件的基础。

定义与语法

变参模板使用 参数包(Parameter Pack),通过 ...语法来表示。
语法:

template <typename... Args>

class MyClass { /* ... */ };

  

template <typename T, typename... Args>

void myFunction(T first, Args... args) { /* ... */ }
变参模板实现方法

一、递归实现

inline void printAll() {  
    std::cout<<std::endl;  
}  
  
template<typename T,typename... Args>  
inline void printAll(const T& first, Args... args) {  
    std::cout<<first<<" ";  
    printAll(args...);  
}
  1. 无参版本:作为递归的终止条件,仅输出一个换行;
  2. 变参模板版本:接收 “第一个参数 + 剩余参数包”,先打印第一个参数,再递归调用自身处理剩余参数,直到参数包为空,触发无参版本

二、折叠表达式(C++17以后)

template<typename... Args>  
void coutAll(const Args&... args) {  
    ((std::cout<<args<<" "), ...);  
    std::cout<<std::endl;  
}

折叠表达式 ((std::cout<<args<<" "), ...)

  • 语法解析

    • ...折叠运算符,作用是 “展开参数包args”;
    • 外层()是折叠表达式的语法要求,内层()是逗号表达式的要求;
    • 逗号运算符,的特性:按顺序执行左侧表达式,最终返回右侧表达式结果(这里只利用 “顺序执行” 的特性,忽略返回值)。
  • 执行过程(以coutAll(10, 3.14, "hello")为例):

    表达式会被编译器展开为:

    (std::cout<<10<<" "), (std::cout<<3.14<<" "), (std::cout<<"hello"<<" ");
    

    即依次执行每个参数的打印操作,实现参数包的遍历。

折叠表达式示例

template<typename... Args>  
auto sumAll(Args... args)->decltype((args + ...)) {  
    return (args + ...);  
}

decltype可以理解为 “类型探测器”:给它一个表达式,它能精准返回这个表达式的类型,哪怕是复杂的、无法手动写出来的类型(比如模板推导的类型、函数返回值类型),decltype的核心是编译期推导表达式的原始类型,保留const、引用、指针等所有属性。

当函数返回值类型依赖于参数类型,且无法用auto直接推导时,decltype能精准匹配。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值