c++模板

在按照书本打代码的时候发现怎么编译都通过不了,都出现了一种未定义的引用的例子,本来觉得可能是自己的CMakeLIsts.txt写错了,之后查找了半天,发现还是因为使用类模板出了错。因为以前也没有使用过类模板,就直接按照普通的类使用.h和.cpp文件将他们分开写了,最后没想到在使用的时候就出现了错误,所以这里就对模板的使用做个记录,免得日后又忘记了。

函数模板

函数模板的定义比较的简单,类型如下所示,这里就举一个加法的例子:

template
T MyAdd(T a, T b)
{
  return a+b;
}

函数模板在使用的时候需要进行实例化,根据具体的数据生成不同的模板函数,与普通函数的调用类似。但是模板函数与普通函数不同的是不允许自动类型转化,比如

int a=1, b=2;
double c=0;
MyAdd(a, b);   //3
MyAdd(a, c);   //error

a和c的数据类型不同,导致了该函数的调用出错了。除此之外,函数模板还有以下的特点:
1、可以被重载
2、如果有普通的函数与它相同,数据类型普通函数可以使用,会优先考虑普通函数
以上的内容在《c++ primer》中也有提到,但是模板是如何编译使用的呢?这里首先需要介绍以下cpp文件编译成可执行文件的过程。

cpp编译过程概况

其实这过程我也不是很了解,只能说一个大概,秉持着知其然可以不知其所以然的态度,所以自己大概的理解就行了吧,一个cpp文件的编译过程可以如下图所示。

image.png

可以通过下面的指令看生成的文件,比如说我的目标cpp文件是index.cpp

g++ -E index.cpp -o index.i
g++ -S index.cpp -o index.s
g++ -C index.s -o index.o
g++ index.s -o index

在linux中可执行文件没有后缀。可以看到cpp文件刚开始就是单独编译,之后再链接其他库文件。

模板函数的编译

编译过程如上述所示,但是模板函数除了本身编译之外,他会按照具体的调用情况再编译一次,一种类型算作一个,这里可以看.s文件来看到底编译了几种类型的模板函数。举个例子:
普通一个代码如下所示:

#include 

template
T myadd(T a, T b)
{
    return a+b;
}

int main()
{
    int a=1, b=2, e=8, f=9;
    double c = 4.8, d = 8.9;
    myadd(a, b);
    myadd(e, f);
    myadd(c, d);
    return 0;
}

之后可以看编译得到的.s文件,因为内容过多,就不都粘贴了,可以看main函数中有三个call,其中前两个是一样的,与最后一个不同,这也说明了如果是同一个类型只需要生成一个实例就行了。

    call    _Z5myaddIiET_S0_S0_
    movl    -20(%rbp), %edx
    movl    -24(%rbp), %eax
    movl    %edx, %esi
    movl    %eax, %edi
    call    _Z5myaddIiET_S0_S0_
    movsd   -8(%rbp), %xmm0
    movq    -16(%rbp), %rax
    movapd  %xmm0, %xmm1
    movq    %rax, -40(%rbp)
    movsd   -40(%rbp), %xmm0
    call    _Z5myaddIdET_S0_S0_

下面,就需要来说说类模板。

类模板

类模板的定义可以如下表示,在使用类模板的时候必须要显示的声明类型,且在类外定义成员函数的时候,需要在前面加上模板类型如:Myclass::***

template 
class Myclass{
//....
};

虽然类的成员函数可以在外面定义,但是他不能像普通的类一样定义分为一个.h文件和.cpp文件。因为在调用该类的时候cpp文件是分开编译的,到最后链接的时候才从头文件去找,但是如果是类用cpp定义的话在编译的就会出错了。
所以,在使用类模板的时候,后缀一般是使用.hpp,这样就不会出错了。

总结

这个也是自己在学习的过程中发现的一个问题,解释的可能不是很清楚,如果有错误的话,敬请批评指正,菜菜需要指导。

你可能感兴趣的:(c++模板)