C++闲谈02——模板元编程

模板

模板介绍

模板定义以关键字template开始,后面跟一个模板参数列表,这是一个以逗号分隔的一个或者多个模板参数的列表

可以将模板看作是编译器函数

模板分类

函数模板

对类型可以参数化

template<typename T>
void swap(T &a, T &b) {
    T tmp;
    tmp = a;
    a = b;
}

类模板

template <typename T>
class compare
{
private:
    T _val;
public:
    explicit compare(T & val) : _val(val) { }
    explicit compare(T && val) : _val(val) { }
    bool operator==(T & t)
    {
        return _val == t;
    }
};

底层原理

template<typename T>
struct Foo
{
    T bar;
    void doSomething(T param) {/* do stuff using T */}
};

// somewhere in a .cpp
Foo<int> f;

如上例子所示,当编译器读到Foo<int>,编译器会创建一个新类,相当于如下

struct FooInt
{
int bar;
void doSomething(int param) {/* do stuff using int */}
}

关键字template告诉编译器,将要定义一个模板

在函数调用点,编译器用用户指定的类型,从原模版实例化一份函数代码出来

bool compare<int> (int a, int b) {
    return a > b;
}

模板实例化(显式实例化 、 隐式实例化)后,编译器会把所有的类参数T换成实例化的类型

C++中模板定义与声明为什么放在同一个文件中

首先明确的是:

对普通函数来说,声明放在头文件中,定义放在源文件中,其它的地方要使用该函数时,仅需要包含头文件即可,因为编译器编译时是以一个源文件作为单元编译的,当它遇到不在本文件中定义的函数时,若能够找到其声明,则会将此符号放在本编译单元的外部符号表中,链接的时候自然就可以找到该符号的定义了。

对于模板。先明确,模板函数是在编译器遇到使用模板的代码时才将模板函数实例化(之前只有函数的模板定义并没有根据函数的使用实现其具体定义)的。若将模板函数声明放在tem.h,模板定义放在tem.cpp,在main.cpp中包含头文件,调用add,按道理说应该实例化int add(int,int)函数,即生成add函数的相应代码,但是此时仅有声明,找不到定义(这里就是需要生成函数的定义),因此此时,它只会实例化函数的符号,并不会实例化函数的实现,即这个时候,在main.o编译单元内,它只是将add函数作为一个外部符号,这就是与普通函数的区别,对普通函数来说,此时的add函数已经由编译器生成相应的代码了,而对模板函数来说,此时并没有生成add函数对应的代码。此时编译main.cpp单元不会报错,但链接就会出现add函数未定义的错误。

其实很明显,明确一点就可以了,即编译器只要遇到使用模板函数时就会实例化相应的函数,若在此编译单元内没有模板函数的定义,它当然不能够实例化成功了。因此通常情况下模板函数的声明与定义均放在同一文件内,因此这样就保证了在使用模板的地方一定可以实例化成功了。

你可能感兴趣的:(C++学习,c++,算法,开发语言)