C++ 泛型编程(五) 模版重载与特例化

前文回顾:
C++ 泛型编程(一) 基本概念
C++ 泛型编程(二) 函数模版
C++ 泛型编程(三) 模版实参推断
C++ 泛型编程(四) 类模板

模版重载

函数模版可以被另一个模版或者一个普通非模版函数重做;名字相同的函数必须具有不同数量或者类型的参数。

  1. 根据参数推断只有一个版本是可行的,则选择该版本

在这里插入图片描述

  1. 都是可行的,匹配更精确的版本

在这里插入图片描述

  1. 都是精确匹配,选择特化版本

在这里插入图片描述

  1. 普通函数可以匹配,选择普通函数

在这里插入图片描述

  1. 通过空模板实参列表限定只匹配模板

在这里插入图片描述

模版特例化

  1. 概念

    ①.特例化:模板,代表了一种泛化的语义,与之相对的就是特化语义。特例化,使得我们能为某些特定的类型专门提供一份特殊实现;特例化本质上是我们顶替了编译器的工作,我们帮编译器做了类型推导。

    ②.全特化:本质上是一个实例,我们必须为模版中每个参数都提供实参。使用关键字 template 加空尖括号对 <> 定义。

    ③.偏特化:本质上还是一个模板,只是原来模板的一个子集。

  2. 函数模版特例化

    ①.定义

    函数模版的不存在偏特化,偏特化即为模版的重载。

    template<class T>
    T add(T a, T b)	{ return a + b;}
    //特例化版本,template<>
    template< >                                 
    double add(double a, double b)  { return a + b; }
    //重载版本,还是模版
    template<class T1>  
    T1 add(T1* a, T1* b) { return *a + *b; }   
    

    ②.头文件

    模版及其特例化版本应该声明在同一个头文件中,所有同名模版的声明应该放在特例化版本之前。

  3. 类模版特例化

    ①.类模版全特化

    跟函数模板一样,全特化是一个实例,当编译器匹配时会优先匹配参数一致的实例。

    //类模版
    template<class T>
    class A
    {
    public:
    	explicit A(T val) : t(val) { }
    	T add(T x) { return t + x; }	
    privete:
    	T t;
    };
    //全特化
    template< >   
    class A<char*>  // 一个全特化的模板类A
    {                
    public:
    	explicit A(char* val) : t(val) { }
    	char* add(char* x) { return strcat(t, x); }
    private:
    	char* t;
    };
    

    ②.偏特化-指定部分参数

    template<class T1, class T2>      // 普通版本,有两个模板参数
    class B { ..... };
    
    template<class T2>            // 偏特化版本,指定其中一个参数,即指定了部分类型
    class B<int , T2> { ..... };  
    

    ③.偏特化-指定参数形式

    template<class T>     // 普通版本
    class B { ..... };
    
    template<class T>   //这个偏特化版本只接收指针类型的模板实参 
    class B<T*> { ..... }; 
    

    ③.特例化成员

    我们也可以只特例化特定成员函数而不是特例化整个模版。

    //类模版
    template <typename T>
    class FOO
    {
    public:
        FOO(const T &t = T()):mem(t){}
        void Bar(){}
    private:
        T mem;
    }
    template<>//全特化
    void FOO<int>::Bar()//特例化 FOO<int> 的一个成员
    {
        
    }
    

可变参数模版

  1. 概念

    ①.可变参数模版:就是可以接受可变数据参数的模版函数和模版类,即参数数量、以及每个参数的类型都未知且各不相同。

    ②.参数包:可变数目的参数称为参数包,用省略号来表示一个包。

    ③.模版参数包:表示零个或者多个模版参数,用 typename… 声明。

    ④.函数参数包:表示零个或者多个函数参数。

    ⑤.sizeof…:获取参数包内参数的数量

    ⑥:Pattern…:以某一模式展开参数包,用省略好触发扩展操作。

  2. 定义可变参数模版

    可变参数模版通常是递归的,参数包Args …在展开的过程中递归调用自己,没调用一次参数包中的参数就会少一个, 直到所有参数都展开为止。

    //Args 是一个模版参数包,表示零个或者多个模版类型的参数
    //rest 是一个函数参数包,表示零个或者多个函数参数
    template<typename T, typename... Args>
    //函数每次分解出一个 val,剩下的再构成一个包
    //模版参数扩展模式:const Args &,对包中每个参数取相同的操作
    //等价于:void print(const T &val, const T1 &t1,const T2 &t2,const T3 &3,const T4 &t4,...)
    void print(const T &val, const Args &... rest)
    {
        //每次打印一个参数
        cout << val << endl;
        //递归继续分解
        //函数参数扩展模式:rest
        //等价于print(rest1,rest2,rest3,rest4,...)
        print(rest...);
    }
    //递归终点
    void print() {}
    
    
  3. 转发参数包

    可变参数函数也可以将它的参数转发给其他函数。模版参数包扩展为一个右值引用的列表,函数参数扩展为一个用 forward 保持类型不变的一个列表。

    template<typename... Args>
    //模版参数扩展模式:Args&&,扩展为右值引用列表
    void fun(Args&&... rest)
    {
        //函数参数扩展模式:forward<Args>(rest),对每个参数取相同操作
        work(std::forward<Args>(rest)...);
    }
    

在这里插入图片描述

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值