• 《C++新经典》第15章 模板与泛型


    15.1 模板概念与函数模板的定义、调用

    15.1.1 模板概念

    vector类模板,通过尖括号<>传递类型参数int,生成真正的类vector
    模板分为函数模板和类模板。

    • 泛型编程独立于任何特定类型的方式编写代码。
    • 模板是泛型编程的基础,是创建类或者函数的蓝图或者公式。
    • 模板机制允许定义类、函数时将类型作为参数。

    15.1.2 函数模板的定义

    int funcadd(int i1, int i2) {
    	int addhe = i1 + i2;
    	return addhe;
    }
    float funcadd(float i1, float i2) {
    	float addhe = i1 + i2;
    	return addhe;
    }
    
    template <typename T> //函数模板,typename或class,类型参数T
    T funcadd(T i1, T i2) {
    	T addhe = i1 + i2;
    	return addhe;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    15.1.3 函数模板的调用

    无法根据提供的实参推断出模板参数时,需要用<>主动提供模板参数。
    编译器推断出模板参数类型后,会实例化特定版本的参数。

    int he = funcadd(3, 1);
    //实例化如下函数:
    int funcadd(int i1, int i2) {
    	int addhe = i1 + i2;
    	return addhe;
    }
    
    float he = funcadd(3.0f, 1.0f);
    //实例化如下函数:
    float funcadd(float i1, float i2) {
    	float addhe = i1 + i2;
    	return addhe;
    }
    
    
    float he = funcadd(3, 1.0f); //编译出错
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    15.1.4 非类型模板参数

    模板参数列表里可以定义非类型参数(表示的是值)。
    非类型模板参数值由用户提供或者编译器推断,必须是常量表达式,因为编译器编译时实例化模板(只有常量表达式才能在编译时确定值)。

    template <int a, int b>
    int funcaddv2() {
    	int addhe = a + b;
    	return addhe;
    }
    
    int result = funcaddv2<12, 13>();//显示指定模板参数,<>中提供额外信息
    
    int a = 12;
    int result = funcaddv2<a, 13>();//错误,a非常量表达式
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    
    template <typename T, int a, int b>
    int funcaddv3(T c) {
    	int addhe = (int)c + a + b;
    	return addhe;
    }
    
    int result = funcaddv3<double, 12, 13>(11);//<>内double与()传递进去的11类型不一致,以<>内传递进去double类型为准,不是以11推断出来的int类型为准。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    template<unsigned L1, unsigned L2>
    int charscomp(char const (&p1)[L1], char const (&p1)[L2]) {
    	return strcmp(p1, p2);
    }
    
    int result = charscomp("test2", "test");
    //实例化版本
    //charscomp(char const (&p1)[6], char const (&p1)[5])
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    #include 
    #include 
    using namespace std;
    
    template<unsigned L1, unsigned L2>
    //inline版本
    inline int charscomp(char const (&p1)[L1], char const (&p2)[L2]) {
    	cout <<L1 <<endl;
    	cout <<L2 <<endl;
    	return strcmp(p1, p2);
    }
    
    int main() {
    	int result = charscomp("test2", "test");
    	cout <<result <<endl;
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    函数模板定义通常放在h头文件中,函数模板定义不会生成相关代码,只有调用函数模板时,编译器才会实例化特定版本函数并生成函数相关代码。

    15.2 类模板概念与类模板的定义、使用

    15.2.1 类模板概念

    实例化特定的类,编译器不能为类模板推断模板参数,模板名后面必须使用"<>"提供模板参数。
    类模板可以避免重复代码,通过传递类型或非类型参数,应付不同数据类型,精简和通用。

    15.2.2 类模板的定义

    template<typename 形参名1, typename 形参名2, ..., typename 形参名n>
    class 类名 {
    	//...
    };
    
    • 1
    • 2
    • 3
    • 4

    类模板的声明和实现等内容,都写到.h文件中去。

    myvector.h

    #ifndef __MYVECTOR__
    #define __MYVECTOR__
    
    template<typename T>
    class myvector {
    public:
    	typedef T* myiterator;
    	//myvector(){};
    	myvector& operator=(const myvector&);
    	//或者myvector& operator=(const myvector<>&);
    	myiterator mybegin(){return &data;};
    	myiterator myend();
    private:
    	T data;
    };
    
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    myvector<int> tmpvec;
    myvector<double> tmpvec2;
    myvector<string> tmpvec3;
    
    • 1
    • 2
    • 3

    15.2.3 类模板的成员函数

    类模板定义中实现的成员函数

    template<typename T>
    class myvector {
    public:
    	myvector(){};
    	void myfunc(){};
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    类模板定义外实现的成员函数

    template<typename T>
    class myvector {
    public:
    	myvector();
    	void myfunc();
    };
    
    template<typename T>
    myvector<T>::myvector(){}
    
    template<typename T>
    void myvector<T>::myfunc(){}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    实例化的模板,它的成员只有在使用的时候(调用)才会被实例化。

    15.2.4 类模板名字的使用

    类模板内部,可以直接使用类模板名,后面可以不加模板参数。

    template<typename T>
    class myvector {
    public:
    	typedef T* myiterator;
    	myvector& operator=(const myvector&);
    	//或者myvector& operator=(const myvector<>&);
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    类模板之外实现。

    template<typename T>
    class myvector {
    public:
    	typedef T* myiterator;
    	myvector& operator=(const myvector&);
    };
    
    
    template<typename T>
    //第一个T表示实例化了的myvector
    //第三个T不是必加
    myvector<T>& myvector<T>::operator=(const myvector<T>&) {
    	return *this;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    15.2.5 非类型模板参数的使用

    template<typename T, int size = 10>
    class myarray {
    public:
    	void myfunc();
    private:
    	T arr[size];
    };
    
    template<typename T, int size>
    void myarray<T, size>::myfunc() {
    	cout <<size <<endl;
    }
    
    myarray<int> tmparr;
    tmparr.myfunc();
    
    myarray<int, 50> tmparr2;
    tmparr2.myfunc();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    //浮点型一般不能作为非类型模板参数
    template<typename T, double size>
    class myarray{};
    
    //类类型不能作为非类型模板参数
    class a{};
    template<typename T, a size>
    class myarray{};
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    15.3 使用typename的场合、函数模板、默认模板参数与趣味写法

    15.3.1 typename的使用场合

    (1)模板定义中表明typename后面的模板参数是类型参数。

    template <typename T, int a, int b>
    int func(T c){...}
    
    template<typename T>
    class myvector{...};
    
    • 1
    • 2
    • 3
    • 4
    • 5

    (2)typename用于标明类型(类型成员):

    //typename标明myvector::myiterator表示类型,而不是静态成员变量。
    template<typename T>
    typename myvector<T>::myiterator myvector<T>::mybegin() {
    	//...
    }
    
    template<typename T>
    typename T::size_type getlength(const T& c) {
    	if(c.empty())
    		return 0;
    	return c.size();
    }
    
    string mytest = "love";
    //size_type类型unsigned int,定义(typedef)在string类中。
    string::size_type size = mytest.size();
    string::size_type size2 = getlength(mytest);
    cout <<size2 <<endl;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    15.3.2 函数指针作为其他函数的参数

    int mf(int tmp1, int tmp2) {
    	return tmp1+tmp2;
    }
    
    typedef int(*FunType)(int,int);
    void testfunc(int i, int j, FunType funcpoint) {
    	cout <<funcpoint(i, j) <<endl;
    }
    
    testfunc(3, 4, mf);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    15.3.3 函数模板趣味用法

    int mf(int tmp1, int tmp2) {
    	return tmp1+tmp2;
    }
    
    typedef int(*FunType)(int,int);
    
    template<typename T, typename F>
    void testfunc(const T& i, const T& j, F funcpoint) {
    	cout <<funcpoint(i, j) <<endl;
    }
    
    //F为函数指针
    testfunc(3, 4, mf);
    
    class tc {
    public:
    	tc() {cout <<"构造函数" <<endl;}
    	tc(const tc& t) {cout <<"拷贝构造函数" <<endl;}
    	//重载()
    	int operator()(int v1, int v2) const {
    		return v1+v2;
    	}
    };
    
    tc tcobj;
    
    //调用拷贝构造函数
    //F为tc
    testfunc(3, 4, tcobj);
    
    //调用构造函数,生成临时对象
    testfunc(3, 4, tc());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    若类重载了"()“运算符,该类实例可调用"对象名(参数)”,看起来像函数调用一样,那么该类生成的对象就是一种可调用对象。

    15.3.4 默认模板参数

    模板参数可以有默认值。

    1. 类模板
      类模板名后"<>“必须有,函数模板多数时候不需要”<>"(编译器推断类型)。
    template<typename T = string, int size = 5>
    class myarray{...};
    
    myarray<> abc;//<>不能省略,类模板且使用默认类型值
    myarray<int> def;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    1. 函数模板
      (1)必须同时为模板参数和函数参数指定默认值。
    template<typename T, typename F = tc>
    void testfunc(const T& i, const T& j, F funcpoint = F()) {
    	cout <<funcpoint(i, j) <<endl;
    }
    
    • 1
    • 2
    • 3
    • 4

    (2)产生临时对象作为默认值。

    void testfunc(const T& i, const T& j, F funcpoint = F()) {
    	cout <<funcpoint(i, j) <<endl;
    }
    //等价于
    void testfunc(const T& i, const T& j, tc funcpoint = tc()) {
    	cout <<funcpoint(i, j) <<endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    (3)tc类必须重载"()"运算符,可调用对象。

    //默认类参数
    class tc {
    public:
    	tc() {cout <<"构造函数" <<endl;}
    	tc(const tc& t) {cout <<"拷贝构造函数" <<endl;}
    	//重载()
    	int operator()(int v1, int v2) const {
    		return v1+v2;
    	}
    };
    template<typename T, typename F = tc>
    void testfunc(const T& i, const T& j, F funcpoint = F()) {
    	cout <<funcpoint(i, j) <<endl;
    }
    
    //默认函数指针参数
    typedef int(*FunType)(int, int);
    int mf(int tmp1, int tmp2) {
    	return tmp1+tmp2;
    }
    template<typename T, typename F = FunType>
    void testfunc(const T& i, const T& j, F funcpoint = mf) {
    	cout <<funcpoint(i, j) <<endl;
    }
    
    testfunc(3, 4);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    15.4 成员函数模板,模板显示实例化与声明

    15.4.1 普通类的成员函数模板

    普通类的成员函数(非虚函数)本身是函数模板。

    class A {
    public:
    	template<typename T>
    	void myft(T tmpt) {
    		cout <<tmpt <<endl;
    	}
    };
    
    A a;
    a.myft(3);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    15.4.2 类模板的成员函数模板

    类模板和其成员函数模板有各自独立的模板参数。

    template<typename C>
    class A {
    public:
    	template<typename T2>
    	A(T2 v1, T2 v2) {}
    
    	template<typename T>
    	void myft(T tmpt) {
    		cout <<tmpt <<endl;
    	}
    	
    	C m_ic;
    };
    
    //成员函数实现代码写到类模板定义之外
    //类模块成员函数定义
    template<typename T2>
    A(T2 v1, T2 v2);
    
    //类模块成员函数实现
    template<typename C>
    template<typename T2>
    A<C>::A(T2 v1, T2 v2) {}
    	
    A<float> a(1, 2);
    A<float> a2(1.1, 2.2);
    a.myft(3);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    15.4.3 模板显示实例化与声明

    模板只有被使用时才会实例化。

    //ca.h
    #ifndef CA_H
    #define CA_H
    
    #include 
    using namespace std;
    
    template<typename C>
    class A {
    public:
    	template<typename T2>
    	A(T2 v1, T2 v2);
    
    	template<typename T>
    	void myft(T tmpt) {
    		cout <<tmpt <<endl;
    	}
    	
    	C m_ic;
    };
    
    template<typename C>
    template<typename T2>
    A<C>::A(T2 v1, T2 v2) {
    	cout <<v1 <<v2 <<endl;
    }
    
    #endif
    
    //test.cpp
    #include "ca.h"
    void mfunc() {
    	A<float> a(1, 2);
    }
    
    //main.cpp
    #include "ca.h"
    int main() {
    	A<float> a(1, 2);
    	A<float> a2(1.1, 2.2);
    	a.myft(3);
    	return 0;
    }
    //test.cpp和main.cpp都会实例化A类。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    显式实例化避免生成多个相同类模板实例的开销。

    //a.h
    #ifndef A_H
    #define A_H
    
    #include 
    using namespace std;
    
    template<typename C>
    class A {
    public:
    	template<typename T2>
    	A(T2 v1, T2 v2);
    
    	template<typename T>
    	void myft(T tmpt) {
    		cout <<tmpt <<endl;
    	}
    	
    	C m_ic;
    };
    extern template A<float>;
    
    template<typename T>
    void myfunc(T v1, T v2);
    extern template void myfunc(int &v1, int& v2);
    
    #endif
    
    
    //a.cpp
    #include "a.h"
    
    template<typename C>
    template<typename T2>
    A<C>::A(T2 v1, T2 v2) {
    	cout <<v1 <<v2 <<endl;
    }
    template A<float>;//会将类模板及所有成员函数都实例化出来,包括内联成员函数。
    
    template<typename T>
    void myfunc(T v1, T v2) {
    	cout <<v1+v2 <<endl;
    }
    template void myfunc(int &v1, int& v2);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    15.5 using定义模板别名与显示指定模板参数

    15.5.1 using定义模板别名

    //typedef给固定类型起别名
    typedef std::map<std::string, int> map_s_i;
    map_s_i mymap;
    mymap.insert({"first", 1});
    
    typedef std::map<std::string, std::string> map_s_s;
    map_s_s mymap2;
    mymap2.insert({"first", "second"});
    
    //c++98通过类模板实现类型名不固定
    template<typename T>
    struct map_s {
    	typedef std::map<std::string, T> type;
    };
    map_s<int>::type map;
    map.insert({"first", 1});
    
    //c++11
    template<typename T>
    using map_s = std::map<std::string, T>;
    map_s<int> map;
    map.insert({"first", 1});
    
    //using用来给类型有关模板起别名
    //using包含了typedef的所有功能
    typedef unsigned int uint_t;
    using uint_t = unsigned int;
    
    typedef std::map<std::string, int> map_s_i;
    using map_s_i = std::map<std::string, int>;
    
    typedef int(*FunType)(int,int);
    using FunType = int(*)(int,int);
    
    
    int RealFunc(int i, int j) {return 3;}
    template<typename T>
    using myfunc_M = int(*)(T,T);
    myfunc_M<int> pointFunc;//类型名,非类模板实例化后的类
    pointFunc = RealFunc;
    cout <<pointFunc(1, 6) <<endl;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    15.5.2 显示指定模板参数

    template<typename T1, typename T2, typename T3>
    T1 sum(T2 i, T3 j) {
    	T1 result = i + j;
    	return result;
    }
    
    auto result = sum(2000000000, 2000000000);//错误,未指定T1
    
    //结果错误,指定T1为int,T2和T3推断为int
    //2000000000+2000000000超出int范围
    auto result = sum<int>(2000000000, 2000000000);
    auto result = sum<double>(2000000000, 2000000000);
    
    //类型不对,编译器报错
    auto result = sum<int, string, string>(2000000000, 2000000000);
    
    //正确
    auto result = sum<double, double, double>(2000000000, 2000000000);
    auto result = sum<double, double>(2000000000, 2000000000);
    
    
    template<typename T1, typename T2, typename T3>
    T3 sum(T1 i, T2 j) {
    	T3 result = i + j;
    	return result;
    }
    //格式不正确
    auto result = sum<, , double>(12, 13);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    15.6 模板全特化与偏特化(局部特化)

    泛化(更宽广的范围),模板就是一种泛化表现,可以指定任意的模板参数。
    特化,类型特殊对待,编写专门的代码。

    15.6.1 类模板特化

    1. 类模板全特化

    1)常规全特化
    泛化的类模板

    template<typename T, typename U>
    struct TC {
    	TC(){
    		cout<<"TC()"<<endl;
    	}
    	void functest(){
    		cout<<"TC::functest()"<<endl;
    	}
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    全特化,就是所有类型模板参数(T和U)都用具体类型代替。

    template<>
    struct TC<int, int> {
    	TC(){
    		cout<<"TC()"<<endl;
    	}
    	void functest(){
    		cout<<"TC::functest()"<<endl;
    	}
    };
    
    template<>
    struct TC<double, int> {
    	TC(){
    		cout<<"TC()"<<endl;
    	}
    	void functest(){
    		cout<<"TC::functest()"<<endl;
    	}
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    TC<char, int> tcchar;
    tcchar.functest();
    
    TC<int, int> tcint;
    tcint.functest();
    
    TC<double, int> tcdouble;
    tcdouble.functest();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    2)特化类模板的成员函数

    template<>
    void TC<double, double>::functest(){
    	cout<<"TC::functest()"<<endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    1. 类模板偏特化(局部特化)

    1)模板参数数量上的偏特化

    template <typename T, typename U, typename W>
    struct TCP {
    	TCP() {
    		cout<<"TCP()"<<endl;
    	}
    	void functest(){
    		cout<<"TCP::functest()"<<endl;
    	}
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    template <typename U>
    struct TCP<int, U, double> {
    	TCP() {
    		cout<<"TCP()"<<endl;
    	}
    	void functest(){
    		cout<<"TCP::functest()"<<endl;
    	}
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    TCP<double, int, double> tcpdi;
    tcpdi.functest();
    
    TCP<int, int, double> tcpii;
    tcpii.functest();
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2)模板参数范围上的偏特化

    template <typename T>
    struct TCF {
    	TCF() {
    		cout<<"TCF()"<<endl;
    	}
    	void functest(){
    		cout<<"TCF::functest()"<<endl;
    	}
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    template <typename T>
    struct TCF<const T> {
    	TCF() {
    		cout<<"TCF()"<<endl;
    	}
    	void functest(){
    		cout<<"TCF::functest()"<<endl;
    	}
    };
    
    template <typename T>
    struct TCF<const T *> {
    	TCF() {
    		cout<<"TCF()"<<endl;
    	}
    	void functest(){
    		cout<<"TCF::functest()"<<endl;
    	}
    };
    
    template <typename T>
    struct TCF<const T&> {
    	TCF() {
    		cout<<"TCF()"<<endl;
    	}
    	void functest(){
    		cout<<"TCF::functest()"<<endl;
    	}
    };
    
    template <typename T>
    struct TCF<const T&&> {
    	TCF() {
    		cout<<"TCF()"<<endl;
    	}
    	void functest(){
    		cout<<"TCF::functest()"<<endl;
    	}
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    TCF<double> td;
    td.functest();
    
    TCF<double*> tcfd;
    tcfd.functest();
    
    TCF<const int> tcfi;
    tcfi.functest();
    
    TCF<int&> tcfyi;
    tcfyi.functest();
    
    TCF<int&&> tcfyii;
    tcfyii.functest();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    15.6.2 函数模板特化

    1. 函数模板全特化
    template <typename T, typename U>
    void tfunc(T& t1, T& t2) {
    	cout<<"tfunc()"<<endl;
    	cout<<t1<<endl;
    	cout<<t2<<endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    template <>
    void tfunc(int& t1, double& t2) {
    	cout<<"tfunc()"<<endl;
    	cout<<t1<<endl;
    	cout<<t2<<endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    //函数重载
    //优先普通函数
    //其次函数模板的特化版本(最最合适的版本)
    //最后函数模板的泛化版本
    void tfunc(int& t1, double& t2) {
    	cout<<"tfunc()"<<endl;
    	cout<<t1<<endl;
    	cout<<t2<<endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    int k=12;
    double db=15.8f;
    tfunc(k, db);
    
    • 1
    • 2
    • 3
    1. 函数模板偏特化

    函数模板不能偏特化.

    //错误
    template <typename U>
    void tfunc<double, U>(double& t1, U& t2) {
    }
    
    • 1
    • 2
    • 3
    • 4

    15.6.3 模板特化版本放置位置

    .h文件中,特化版本放在泛化版本后面。

    15.7 可变参模板与模板模板参数

    Variadic Templates,0到任意个模板参数,…

    15.7.1 可变参函数模板

    template<typename... T>
    void func(T... args){
    	cout<<sizeof...(args)<<endl;
    	cout<<sizeof...(T)<<endl;//同上
    }
    
    func();
    func(10, 2.3, "abc");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    args称为一包或者一堆参数,0到多个不同类型.

    template<typename T, typename... U>
    void func2(const T& firstarg, const U&... otherargs){
    	//cout<
    	cout<<sizeof...(otherargs)<<endl;
    }
    
    //func2();//error
    func2(10);
    func2(10, 2.3, "abc");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    1. 参数包的展开
    void func3() {
    	cout<<"Over!"<<endl;
    }
    
    template<typename T, typename... U>
    void func3(const T& firstarg, const U&... otherargs){
    	cout<<firstarg<<endl;
    	cout<<func3(otherargs...)<<endl;
    }
    
    func2(10, 2.3, "abc");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    15.7.2 可变参类模板

    1. 通过递归继承方式展开参数包
    template<typename... Args>
    class myclasst{
    public:
    	myclasst(){
    		printf("myclasst::myclasst(), this = %p\n", this);
    	}
    };
    
    template<typename First, typename... Others>
    classt<First, Others...>:private myclasst<Others...>{
    public:
    	myclasst():m_i(0){
    		printf("myclasst::myclasst(), this = %p, sizeof...(Others) = %d\n", this, sizeof...(Others));
    	}
    	First m_i;
    };
    
    myclasst<int, float, double> myc;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    template<>
    class myclasst<>{
    public:
    	myclasst(){
    		printf("myclasst<>::myclasst(), this = %p\n", this);
    	}
    };
    
    template<typename First, typename... Others>
    classt<First, Others...>:private myclasst<Others...>{
    public:
    	myclasst():m_i(0){
    		printf("myclasst::myclasst(), this = %p, sizeof...(Others) = %d\n", this, sizeof...(Others));
    	}
    	myclasst(First parf, Others... paro):m_i(parf),myclasst<Others...>(paro...){
    		cout<<"begin"<<endl;
    		printf("myclasst::myclasst(parf, ...paro), this = %p, sizeof...(Others) = %d\n", this, sizeof...(Others));
    		cout<<"m_i="<<m_i<<endl;
    		cout<<"end"<<endl;
    	}
    	First m_i;
    };
    
    myclasst<int, float, double> myc(12, 13.5, 23);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    1. 通过递归组合方式展开参数包
    template<typename First, typename... Others>
    class myclasst<First, Others...>{
    public:
    	myclasst():m_i(0){
    		printf("myclasst::myclasst(), this = %p\n", this);
    	}
    	myclasst(First parf, Others... paro):m_i(parf),m_o(paro...){
    		cout<<"begin"<<endl;
    		printf("myclasst::myclasst(parf, ...paro), this = %p, sizeof...(Others) = %d\n", this, sizeof...(Others));
    		cout<<"m_i="<<m_i<<endl;
    		cout<<"end"<<endl;
    	}
    	First m_i;
    	myclasst<Others...> m_o;
    };
    
    myclasst<int, float, double> myc(12, 13.5, 23);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    1. 通过tuple和递归调用展开参数包

    tuple,元组,可以装各种不同类型的元素(数据)。

    template<typename...T>
    void functuple(const tuple<T...> &t){}
    
    
    tuple<float, int, int> mytuple(12.5f, 100, 52);
    cout<<get<0>(mytuple)<<endl;
    
    functuple(mytuple);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    template<int mycount, int mymaxcount, typename ...T>
    class myclasst2{
    public:
    	static void mysfunc(const tuple<T...> &t){
    		cout<<"value = "<<get<mycount>(t)<<endl;
    		myclasst2<mycount+1, mymaxcount, T...>::mysfunc(t)
    	}
    };
    
    template<int mymaxcount, typename ...T>
    class myclasst2<mymaxcount, mymaxcount, T...>{
    public:
    	static void mysfunc(const tuple<T...> &t){
    	}
    };
    
    
    template<typename ...T>
    void myfunctuple(const tuple<T...> &t){
    	myclasst2<0, sizeof...(T), T...>::mysfunc(t);
    }
    
    tuple<float, int, int> mytuple(12.5f, 100, 52);
    myfunctuple(mytuple);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    15.7.3 模板模板参数

    模板参数本身是一个模板。

    template<
    	typename T,
    	//template class Container
    	template<typename W> typename Container//W可省略
    >
    
    class myclass{
    public:
    	myclass(){
    		for(int i=0; i<10; i++)
    			myc.push_back(i);
    	}
    public:
    	T m_i;
    	Contianer<T> myc;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    template<typename T>
    using MYVec = vector<T, allocator<T>>;
    
    template<typename T>
    using MYList = list<T, allocator<T>>;
    
    myclass<int, MYVec> myvecobj;
    myclass<int, MYList > mylistobj;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
  • 相关阅读:
    C++11:自动类型推导auto/decltype
    一文带你享受数学之优美
    Vue3使用Vite创建项目
    【postgresql 基础入门】psql客户端的使用方法
    JVM第十三讲:调试排错 - JVM 调优参数
    前端学习C语言 - 数组和字节序
    1076 Forwards on Weibo
    【Nano Framework ESP32篇】使用 LCD 屏幕
    Java进阶总结——集合
    APP瀑布流分页问题——领取,使用等操作即消失问题
  • 原文地址:https://blog.csdn.net/oqqyx1234567/article/details/124464838