c++ 模版template

 

函数模板

template <class identifier> function_declaration;

template <typename identifier> function_declaration;

注意class与typename意义一样,可以互换

例如:

//A.h

template<typename T> void swap(T& t1, T& t2);

//A.cpp

template<typename  T> void swap(T& t1, T& t2) {

    T tmpT;

    tmpT = t1;

    t1 = t2;

    t2 = tmpT;

}

 简单类模板示例

类模板声明(.h,.hpp文件)
//myTemplate.h
template <class T> class Stack {
    public:
        Stack();
        ~Stack();
        void push(T t);
        T pop();
        bool isEmpty();
    private:
        T *m_pT;        
        int m_maxSize,m_size;
};

类模板定义(cpp文件)

//myTemplate.cpp

template <class  T>  Stack<T>::Stack(){m_maxSize = 100; m_size = 0;m_pT = new T[m_maxSize];}

template <class T>  Stack<T>::~Stack() { delete [] m_pT ;}

template <class T> void Stack<T>::push(T t) { m_size++; m_pT[m_size - 1] = t; }

template <class T> T Stack<T>::pop() { T t = m_pT[m_size - 1]; m_size--; return t; }

template <class T> bool Stack<T>::isEmpty() { return m_size == 0; }

 带有常规参数的(且参数分配默认值)的类模板示例

下述类模板栈定义,规定默认最多支持100个元素,使用时可以使用模板参数配置栈最大元素数,如果不配置,则默认最大值为100:

//statck.h
template <class T,int maxsize = 100> class Stack {
    public:
        Stack();
        ~Stack();
        void push(T t);
        T pop();
        bool isEmpty();
        int capacity(){return m_maxSize;}
    private:
        T *m_pT;        
        int m_maxSize, m_size;
};
//stack.cpp
template <class T,int maxsize> Stack<T, maxsize>::Stack(){
   m_maxSize = maxsize;      m_size = 0; m_pT = new T[m_maxSize];}
template <class T,int maxsize>  Stack<T, maxsize>::~Stack() {delete [] m_pT ;}
template <class T,int maxsize> void Stack<T, maxsize>::push(T t) {
    m_size++;m_pT[m_size - 1] = t;}
template <class T,int maxsize> T Stack<T, maxsize>::pop() {
    T t = m_pT[m_size - 1];m_size--;return t;}
template <class T,int maxsize> bool Stack<T, maxsize>::isEmpty() {
    return m_size == 0;}
//main.cpp
#include <stdio.h>
#include "stack.h"
int main() {
    int maxsize = 1024;
    Stack<int,1024> intStack;
    for (int i = 0; i < intStack.capacity(); i++) {intStack.push(i);}
    while (!intStack.isEmpty()) {
        printf("num:%d\n", intStack.pop());
}
Stack<int> defaultStack;
    for (int i = 0; i < defaultStack.capacity(); i++) {defaultStack.push(i);}
    while (!defaultStack.isEmpty()) {
        printf("num:%d\n", defaultStack.pop());
    }
    return 0;
}

 

 模板的实例化与特化

概述
模板函数不是真正的函数定义,只是如其名提供一个模板,因此必须要提供实话例的代码方可使用(从编译原理与代码段生成来理解,即编译的二进制代码中必须存在有具体使用类型的模板类或代码,方可运行使用,否则链接不到具体代码,链接失败),实例化分隐式实例化与显式实例化两种。
隐式实例化
(implicit instantiation)
在具体使用位置创建:
int main(){  
   ....  
   swap<int>(a,b);  
   ....  
}
编译器运行编译到此处时,会自动根据模板应用的具体类型生成相应的实例代码段,很显然,这影响编译效率。这里顺便提一下swap<int>(a,b);中的<int>是可选的,因为编译器可以根据函数参数类型自动进行判断,即如果编译器不能自动判断的时候这是必要的;
显式实例化
(implicit instantiation)
隐式实例化影响效率,提高效率则使用显式实例化,显式实例化在编译期间无论代码类型是否使用,均会生成实例,方法如下:
在cpp文件根据需要的类型中定义如下行:
template void swap<int>(int &a,int &b);  
注意:如果模板头文件做成dll 头文件方式输出,则必须要在dll内部cpp文件进行显示实例化或或隐式实例化,不可将实例化留给dll调用者进行,否则编译不过(避免实例在多个调用者程序中,这也不符合dll的原始精神)
特化
(specialization,也译作具体化或专门化)
 
 

 

 模板别名(c++11)

template<typename T> using twin = std::pair<T, T>;
template<typename T> using str_int = std::pair<T, int>;

std::cout<<"test template alias:\n";
twin<std::string> twin_str = {"abc", "def"};
std::cout<<"twin_str:\t"<<twin_str.first<<'\t'<<twin_str.second<<std::endl;
str_int<std::string> strno = {"abc", 100};
std::cout<<"strno:\t"<<strno.first<<'\t'<<strno.second<<std::endl;
std::cout<<"test template alias done.\n"<<std::endl;

  尾置返回类型(c++11)

当时用模板定义一个函数时,有时函数的返回类型是和模板参数相关的,这时可以通过decltype获得返回类型。
template<typename It> auto get_begin(It  beg) -> decltype(*beg){
    return *beg;
}
std::cout<<"test tail return type of template:\n";
std::vector<int> numbers = {1, 2, 3, 4, 5};
std::cout<<"get_begin:\t"<<get_begin(numbers.begin())<<std::endl;
std::cout<<"test tail return type of template done.\n";

 

 

不定长模板(c++11)
新标准中,可定义不定长度的模板参数列表。这种形式,一般和递归结合使用。
template<typename T> std::ostream &print_variadic(std::ostream &os, const T &t){
    return os<<t<<std::endl;
}
template<typename T, typename... Args>
std::ostream &print_variadic(std::ostream &os, const T &t, const Args&... rest){
    os<<t<<"(remain size: "<<sizeof...(Args)<<"), ";
    return print_variadic(os, rest...);
}
std::cout<<"test variadic template:\n";
print_variadic(std::cout, 100, "s", 56.76, 101);
std::cout<<"test variadic template done.\n";
第一次为print_variadic传入了4个需要打印的对象,则实例化第二个不定长模板函数,将100赋值给t,并将剩余的3个参数打包成rest。
在内部递归中,将不断的将rest包中的第一个参数拿出来付给t,剩余参数打包进行下一次递归调用。最后只剩一个参数时,两种形式的print_variadic都可以匹配,但是第一种没有模版参数包的版本更加特例化,因此将调用第一种形式的print_variadic,结束递归。

 

 默认参数(c++11)

c++11中,可以像为函数提供默认参数一样,为模板参数提供默认值。

template<typename T, typename F=std::less<T>>

int compare(const T &v1, const T &v2, F f=F()){

    if(f(v1, v2)) return -1;

    if(f(v2, v1)) return 1;

    return 0;

}

cout<<"test default template param:\n";

cout<<"compare int 1 2:\t" << compare(1, 2) << endl;

cout<<"compare int 2.0 1.0:\t" << compare(2.0, 1.0) << endl;

cout<<"test default template param done.\n" << endl;

  模板友元(c++11)

声明一个类的模板参数类型为类的友元。
template<typename T> class Bar {
friend T;
protected:
    int val = 100;
};
class Foo{
public:
    void print_bar(Bar<Foo> &bar) { cout << "bar:\t" << bar.val << endl; }
};
cout<<"test friend template type:\n";
Bar<Foo> bar;
Foo foo;
foo.print_bar(bar);
cout<<"test friend template type done.\n"<<endl;
由于友元机制,在Foo中可以直接访问到Bar的protected属性val。
posted @ 2019-06-24 11:17  Reboost  阅读(379)  评论(0)    收藏  举报