一起学习交流~

c/c++细节知识点 16模板

目录

原理

/*
在某些情况下重载的效率比较低,如果两个函数执行的操作相同,仅仅是类型不同,用重载就需要重新写一个函数
模板就是为了解决这种问题

模板的格式为:
template<class Type> template<typename Type>
class和typename在声明模板参数类型时时相同的,而且在很多情况下都是相同的,但某些特殊情况必须使用typename
比如在类中使用范围解析运算符,调用静态变量和类型在写法上是相同的
比如 A::NUM你无法判断这个NUM是类型还是静态变量(编译器默认为静态变量)
此时就会造成编译错误,要变为语法错误则必须用typename来标识为类型

模板的工作原理
模板并不是真的实现了泛型,而是在编译时根据传入的类型来自己写出对应版本的定义,
编译器写出的版本通常被称为模板的实例,这个过程叫做模板实例化

模板可以有默认参数,不在<>中填类型则使用模板的默认参数作为类型

可变参数模板
c++11中新增特性,允许模板定义任意个模板参数
如:
void show(){}//防止死循环
template<class T,class... ARGS>
void show(const T& val,ARGS... args){
    cout<<val<<endl;
    show(args...);//往后递归
}

非类型模板参数(经常用于模板元编程)
模板的参数不是类型,而是变量

函数模板和类模板叫做泛化,如果需要指定某几种类型特别处理,叫做特化
特化分为全特化和偏特化
模板特例化有以下几种情形
1.函数模板特例化
必须为所有函数模板的参数都提供实参(全特化)(理论上是这样,但实际上可以用重载的方式只特例化部分,实现偏特化)
2.类模板特例化
2.1类模板的部分参数特例化(全特化)
2.2类模板的所有参数特例化(偏特化)
2.3类模板的某个成员函数特例化

优先级为
模板泛化<模板特化<重载
如果重载了模板,特化一部分,那么后定义的优先级高(代码是栈的方式读取的)
*/

代码

/*
模板的简单用法
假设交换两个变量的值
*/
//如果需要交换其它类型,比如string,那么就必须重新写一个参数为string的
void func16_1_1(int& a, int& b) {
    int c = a;
    a = b;
    b = c;
}
//使用模板可以不指定类型,在编译时编译器会根据调用了该模板的类型自动生成对应的函数
//在这里typename和class效果相同
template<typename TYPE>
void func16_1_2(TYPE&t1,TYPE&t2) {
    TYPE t3 = t1;
    t1 = t2;
    t2 = t3;
}
int main16_1() {
    int a = 123;
    int b = 321;
    func16_1_1(a, b);
    cout << a << " " << b << endl;
    func16_1_2<int>(a, b);
    cout << a << " " << b << endl;
    string s1 = "asd";
    string s2 = "123";
    func16_1_2<string>(s1, s2);
    cout << s1 << " " << s2 << endl;
    return 0;
}
/*
class和tpypename区别
范围解析运算符在模板中默认::右边是变量而不是类型
如果需要解析为类型需要用通过typename
*/
template<class T>
class Class16_2_A{
public:
    T container;
    Class16_2_A(const T& container) {
        this->container = container;
    }
    //此时不加typename则编译报错
    //因为编译器不知道 const T::iterator 是类型还是变量
    typename const T::iterator begin() {
        return container.begin();
    }
};
int main16_2() {
    Class16_2_A<vector<int>> container(vector<int>{123,213,321});
    cout << *container.begin() << endl;
    return 0;
}

/*
模板默认参数
此时不填参数默认为double
*/
template<class T = double>
T func16_add(const T&t1 ,const T&t2) {
    return t1 + t2;
}

/*
可变参数模板
*/
void show() {}//防止死循环
template<class T, class... ARGS>
void show(const T& val, ARGS... args) {
    cout << val << endl;
    show(args...);//往后递归
}
int main16_args() {
    show(1, 2, 3, 4, 5, 6);
    return 0;
}

/*
函数模板泛化特化
*/
//泛化
template<typename T1,typename T2>
void func16_1(T1& x,T2& y) {
    cout << "do some thing" << endl;
}
//虽然可以部分特例化,但此时应该叫重载,因为与函数重载冲突了
template<typename T>
void func16_1(T& x, int& y) {
    cout << "特例化 T int" << endl;
}
//特例化
template<>
void func16_1(string& x, int& y) {
    cout << "特例化 string int" << endl;
}

//特例化,<int&,int&>其实可以省略掉
template<>
void func16_1(int& x, int& y) {
    cout << "特例化 int int" << endl;
}

//非特化,函数重载,优先级高于模板特例化
void func16_1(int& x, int& y) {
    cout << "重载" << endl;
}

int main16_func() {
    string s = "abcd";
    int num = 123;
    func16_1(s, num);
    func16_1(num, num);
    return 0;
}

/*
类模板泛化特化
*/
//类模板泛化
template<typename Type,typename Container>
class Class16_Array {
private:
    Container container;
public:
    Class16_Array() { cout << "泛化 : Type,Container" << endl; }
    const size_t size()const { return container.size(); }
    void add(const Type&value) { container.insert(container.end(), value); }
    const Type& get(int position) { return container.at(position); }
};

//类模板偏特化
//只特例化部分,比如 如果容器使用list,则使用该代码
template<typename Type>
class Class16_Array<Type,list<Type>> {
private:
    list<Type> container;
public:
    Class16_Array() { cout << "偏特化 : Type,list<Type>" << endl; }
    const size_t size()const { return container.size(); }
    void add(const Type& value) { container.push_back(value); }
    const Type& get(int position) {
        typename list<Type>::iterator begin = container.begin();
        for (int i = 0; i < position; i++) begin++;
        return *begin;
    }
};

//类模板全特化
//全部特例化,指定所有模板参数
template<>
class Class16_Array<int, unordered_set<int>> {
private:
    unordered_set<int> container;
public:
    Class16_Array() { cout << "全特化 : int,unordered_set<int>" << endl; }
    const size_t size()const { return container.size(); }
    void insert(const int& val) { container.insert(val); }
    bool find(const int& val) { return container.find(val)!=container.end(); }
};

int main16Class() {
    Class16_Array<string, vector<string>> stringArray;
    stringArray.add("hello");
    cout << stringArray.get(0) << endl;

    Class16_Array<int, vector<int>> intArray;
    intArray.add(123);
    cout << intArray.get(0) << endl;

    Class16_Array<double, vector<double>> doubleArray;
    doubleArray.add(123.321);
    cout << doubleArray.get(0) << endl;

    cout << endl;

    Class16_Array<string, list<string>>stringList;
    stringList.add("hello");
    cout << stringList.get(0) << endl;

    Class16_Array<int, list<int>> intList;
    intList.add(123);
    cout << intList.get(0) << endl;

    Class16_Array<double, list<double>> doubleList;
    doubleList.add(123.321);
    cout << doubleList.get(0) << endl;

    cout << endl;

    Class16_Array<int, set<int>> intSet;
    intSet.add(123);
    cout << intSet.size() << endl;

    //只有全部参数都是类模板特化的参数才是全特化
    Class16_Array<int, unordered_set<int>> intUSet;
    intUSet.insert(123);
    cout << intUSet.size() << endl;
    return 0;
}

//类模板中的成员函数特化
template<typename T1,typename T2>
class Class16_ClassFunc {
public:
    void say() { cout << "hello" << endl; }
    //void say()<int,double> { cout << "hello word" << endl; }
    //template<>void say() < int, double > { cout << "hello word" << endl; }
};
//值得注意的是,类模板中的成员函数特例化只能在类外部实现
template<>
void Class16_ClassFunc<int,double>::say() {cout << "hello word" << endl;}

int main() {
    Class16_ClassFunc<int, int>f1;
    Class16_ClassFunc<int, vector<int>>f2;
    Class16_ClassFunc<int, double>f3;
    f1.say();
    f2.say();
    f3.say();
    return 0;
}
喜欢 (0)
订阅评论
提醒
guest
0 评论
内联反馈
查看所有评论