c++ 模板之函数模板

不太清楚模板,也没怎么用过,无奈最近看代码,老是出现模板,觉得一来看代码费劲了,而来,这个东西同事说很好,我也看看,如果好的话,我写的时候也用用,看了俩例子,记录下来,时而温习

温故而知新,而且每次温习必定有不同的体会。

实现一个加法的功能

首先看下,不用模板的代码
#include <iostream>
using namespace std;
int add(int a, int b);
float add(float a, float b);
float addFloat(float a, float b);

int main (int argc, const char * argv[])
{

    int x = 1, y = 2;
    cout<<"x +y = "<<add(x, y)<<endl;
    float m = 1.0f, n = 2.0f;
    cout<<"m + n = "<<add(m, n)<<endl;
    
    return 0;
}
int add(int a, int b){
    return a + b;
}
float add(float a, float b){
    return a + b;
}
float addFloat(float a, float b){
    return a + b;
}

 运行可以得到结果 
x +y = 3
m + n = 3
Program ended with exit code: 0

然后,这个应用了c++的重载的功能,两个函数,但是都叫一个名字,不然,真得用下面那个addFloat函数进行计算,但是重载跟模板应该说是有关系的,都是为了把类型忽略掉,但是又不同,具体后面阐述

现在用模板,模板是为了忽略掉类型,所以,再也没有int,float了,统一用一个类型T代替,然后调用的时候,再把类型传过来,这样就知道T的具体类型了,代码看下

#include <iostream>
using namespace std;
template<typename T>
T add(T a, T b);

int main (int argc, const char * argv[])
{

    int x = 1, y = 2;
    cout<<"x +y = "<<add(x, y)<<endl;
    float m = 1.0f, n = 2.0f;
    cout<<"m + n = "<<add(m, n)<<endl;
    
    return 0;
}
template<typename T>
T add(T a, T b){
    return a + b;
}

同样输出了正确的结果,这个时候,即使又来了新的类型,也能输出正确的结果,但是如果只用重载的话,就会失败了


模板和重载

重载是函数名相同,参数类型或者参数个数不同的函数,虽然在写的时候他们的名字是相同的,但是其实编译的时候并不相同,

看一下第一次的重载实现的可执行文件的汇编代码
================ B E G I N   O F   P R O C E D U R E ================


                                       ; Basic Block Input Regs: rsp rsi rdi -  Killed Regs: rax rbp rsi
                                            __Z3addii_100000d50:        // add(int, int)
0000000100000d50 55                              push       rbp                           ; XREF=0x100000cd1
0000000100000d51 4889E5                          mov        rbp, rsp
0000000100000d54 897DFC                          mov        dword [ss:rbp-0x0+var_m4], edi
0000000100000d57 8975F8                          mov        dword [ss:rbp-0x0+var_m8], esi
0000000100000d5a 8B75FC                          mov        esi, dword [ss:rbp-0x0+var_m4]
0000000100000d5d 0375F8                          add        esi, dword [ss:rbp-0x0+var_m8]
0000000100000d60 89F0                            mov        eax, esi
0000000100000d62 5D                              pop        rbp
0000000100000d63 C3                              ret        
                        ; endp
0000000100000d64 6666662E0F1F840000000000        nop        word [cs:rax+rax+0x0]


================ B E G I N   O F   P R O C E D U R E ================


                                       ; Basic Block Input Regs: rsp xmm0 xmm1 -  Killed Regs: rbp xmm0
                                            __Z3addff_100000d70:        // add(float, float)
0000000100000d70 55                              push       rbp                           ; XREF=0x100000d20
0000000100000d71 4889E5                          mov        rbp, rsp
0000000100000d74 F30F1145FC                      movss      dword [ss:rbp-0x0+var_m4], xmm0
0000000100000d79 F30F114DF8                      movss      dword [ss:rbp-0x0+var_m8], xmm1
0000000100000d7e F30F1045FC                      movss      xmm0, dword [ss:rbp-0x0+var_m4]
0000000100000d83 F30F5845F8                      addss      xmm0, dword [ss:rbp-0x0+var_m8]
0000000100000d88 5D                              pop        rbp
0000000100000d89 C3                              ret        
                        ; endp
0000000100000d8a 660F1F440000                    nop        word [ds:rax+rax+0x0]


可以看到两个函数被编译成了两个函数,名字不一样,然后main函数调用的时候,也会调用call 指令指向不同的地址

那么其实跟写成addFloat没什么区别,只是在写法上和可读性上提升了很多


模板呢?会怎么样
看下汇编代码
================ B E G I N   O F   P R O C E D U R E ================


                                       ; Basic Block Input Regs: rsp rsi rdi -  Killed Regs: rax rbp rsi
                                            __Z3addIiET_S0_S0__100000df0:        // int add<int>(int, int)
0000000100000df0 55                              push       rbp                           ; XREF=0x100001058
0000000100000df1 4889E5                          mov        rbp, rsp
0000000100000df4 897DFC                          mov        dword [ss:rbp-0x0+var_m4], edi
0000000100000df7 8975F8                          mov        dword [ss:rbp-0x0+var_m8], esi
0000000100000dfa 8B75FC                          mov        esi, dword [ss:rbp-0x0+var_m4]
0000000100000dfd 0375F8                          add        esi, dword [ss:rbp-0x0+var_m8]
0000000100000e00 89F0                            mov        eax, esi
0000000100000e02 5D                              pop        rbp
0000000100000e03 C3                              ret        
                        ; endp
0000000100000e04 6666662E0F1F840000000000        nop        word [cs:rax+rax+0x0]


================ B E G I N   O F   P R O C E D U R E ================


                                       ; Basic Block Input Regs: rsp xmm0 xmm1 -  Killed Regs: rbp xmm0
                                            __Z3addIfET_S0_S0__100000e10:        // float add<float>(float, float)
0000000100000e10 55                              push       rbp                           ; XREF=0x100001050
0000000100000e11 4889E5                          mov        rbp, rsp
0000000100000e14 F30F1145FC                      movss      dword [ss:rbp-0x0+var_m4], xmm0
0000000100000e19 F30F114DF8                      movss      dword [ss:rbp-0x0+var_m8], xmm1
0000000100000e1e F30F1045FC                      movss      xmm0, dword [ss:rbp-0x0+var_m4]
0000000100000e23 F30F5845F8                      addss      xmm0, dword [ss:rbp-0x0+var_m8]
0000000100000e28 5D                              pop        rbp
0000000100000e29 C3                              ret        
                        ; endp

同样有两个,那我如果再调用一次呢,增加一个string的
string u = "aaa", v = "bbb";
cout<<"u + v = " <<add(u, v)<<endl;

相应的汇编代码,也会增加一个函数

================ B E G I N   O F   P R O C E D U R E ================


                                       ; Basic Block Input Regs: rdi -  Killed Regs: rax rsp rbp
                                            __Z3addISsET_S0_S0__100001b10:        // std::string add<std::string>(std::string, std::string)
0000000100001b10 55                              push       rbp                           ; XREF=0x100002060
0000000100001b11 4889E5                          mov        rbp, rsp
0000000100001b14 4883EC10                        sub        rsp, 0x10
0000000100001b18 4889F8                          mov        rax, rdi
0000000100001b1b 488945F8                        mov        qword [ss:rbp-0x10+var_8], rax
0000000100001b1f E80A010000                      call       imp___stubs___ZStplIcSt11char_traitsIcESaIcEESbIT_T0_T1_ERKS6_S8_
0000000100001b24 4883C410                        add        rsp, 0x10
0000000100001b28 5D                              pop        rbp
0000000100001b29 C3                              ret        
                        ; endp
0000000100001b2a 660F1F440000                    nop        word [ds:rax+rax+0x0]

看来模板是用到的时候展开,但是函数不用显示的传递变量的类型,他自己就会识别了









评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值