/*
 * 为什么要特化?
 *     因为编译器认为,对于特定的类型,如果你对某一功能有更好的实现,那么就该听你的。
 * 模板分类:
 *     类模板/函数模板
 * 特化分类:
 *     全特化
 *         全特化就是限定死模板的实现的具体类型。 
 *     偏特化
 *         偏特化就是模板如果有多个类型,那么只限定其中一部分,
 *         细分还可以分为: 范围偏特化和个数偏特化。
 *         个数的偏特化从左到右。
 * 优先级:
 *     全特化 > 偏特化 > 泛化
 * 注意事项:
 *         C++标准规定, 函数模板只有泛化与全特化,不能偏特化, 
 *         有些编译器实现了,所以可以。
 * 
*/

#include <iostream>

template <typename T1, typename T2>
class A {
public:
        void function(T1 v1, T2 v2) {
                std::cout << "类模板泛化" << std::endl;
        }
};

template<>      // 类型明确, 全特化,所以参数列表为空
class A<int, double> {
public:
        void function(int v1, double v2){
                std::cout << "类模板全特化" << std::endl;
        }
};

template<typename T2>
class A<int, T2>{       // 由于指定了一部分, 剩下未指定的需要在参数列表中,否则报错
public:
        void function(int v1, T2 v2){
                std::cout << "类模板个数偏特化" << std::endl;
        }
};

template<typename T1, typename T2>
class A<T1*, T2*>{      // 这是范围上的偏
public:
        void function(T1* v1, T2* v2){
                std::cout << "类模板指针偏特化" << std::endl;
        }
};

template<typename T1, typename T2>
class A<T1 const, T2 const>{    // 这是范围上的偏
public:
        void function(T1 v1, T2 v2){
                std::cout << "类模板const偏特化" << std::endl;
        }
};


void TestClassTemplate(){
        // 泛化
        A<int, int> a;
        a.function(12, 12);

        // 全特化
        A<int, double> aa;
        aa.function(12, 12.3);

        // 个数偏特化
        A<char, int> aaa;
        aaa.function('a', 12);

        int x;
        // 指针范围偏特化
        A<int*,int*> aaaa;
        aaaa.function(&x, &x);

        // const范围偏特化
        A<const int,const int> aaaaa;
        aaaaa.function(11, 22);
}

template<typename T1, typename T2>
void function(T1 v1, T2 v2){
        std::cout << "函数泛化" << std::endl;
}

template<>
void function(char v1, double v2){
        std::cout << "函数全特化" << std::endl;
}

// 函数模板不允许有偏特化
/* template<typename T2> */
/* void function(T2 v1, char v2){ */
/*      std::cout << "函数偏特化" << std::endl; */
/* } */

void TestFunctionTemplate(){
        // 泛化
        function(1, 1);
        // 全特化
        function('a', 1.2);
}


int main(){
        TestClassTemplate();
        TestFunctionTemplate();
        return 0;
}