思考:为什么函数模板能够和函数重载放在一块。C++编译器是怎样提供函数模板机制的?

demo 1

#include <cstdio>
#include <iostream>
using namespace std; // 1.cpp // g++ -S 1.cpp -o 1.s
template <typename T>
void myswap(T &a, T &b)
{
T c = 0;
c = a;
a = b;
b = c;
cout << "hello ....我是模板函数 欢迎 calll 我" << endl;
} int main()
{
{ int x = 10;
int y = 20; myswap<int>(x, y); //1 函数模板 显示类型 调用 printf("x:%d y:%d \n", x, y);
} {
char a = 'a';
char b = 'b'; myswap<char>(a, b); //1 函数模板 显示类型 调用
printf("a:%c b:%c \n", a, b);
}
return 0;
}

把demo 1编译成汇编文件,查看:

	.file	"1.cpp"
.lcomm __ZStL8__ioinit,1,1
.def ___main; .scl 2; .type 32; .endef
.section .rdata,"dr"
LC0:
.ascii "x:%d y:%d \12\0"
LC1:
.ascii "a:%c b:%c \12\0"
.def ___gxx_personality_sj0; .scl 2; .type 32; .endef
.def __Unwind_SjLj_Register; .scl 2; .type 32; .endef
.def __Unwind_SjLj_Unregister; .scl 2; .type 32; .endef
.text
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
pushl %ebp
movl %esp, %ebp
pushl %edi
pushl %esi
pushl %ebx
andl $-16, %esp
subl $96, %esp
movl $___gxx_personality_sj0, 52(%esp)
movl $LLSDA959, 56(%esp)
leal 60(%esp), %eax
movl %ebp, (%eax)
movl $L5, %edx
movl %edx, 4(%eax)
movl %esp, 8(%eax)
leal 28(%esp), %eax
movl %eax, (%esp)
call __Unwind_SjLj_Register
call ___main
movl $10, 92(%esp)
movl $20, 88(%esp)
leal 88(%esp), %eax
movl %eax, 4(%esp)
leal 92(%esp), %eax
movl %eax, (%esp)
movl $1, 32(%esp)
<span style="color:#ff0000;"> call __Z6myswapIiEvRT_S1_ // 41 call 117</span>
movl 88(%esp), %edx
movl 92(%esp), %eax
movl %edx, 8(%esp)
movl %eax, 4(%esp)
movl $LC0, (%esp)
call _printf
movb $97, 87(%esp)
movb $98, 86(%esp)
leal 86(%esp), %eax
movl %eax, 4(%esp)
leal 87(%esp), %eax
movl %eax, (%esp)
movl $2, 32(%esp)
<span style="color:#ff0000;"> call __Z6myswapIcEvRT_S1_ // 55 call 145</span>
movb 86(%esp), %al
movsbl %al, %edx
movb 87(%esp), %al
movsbl %al, %eax
movl %edx, 8(%esp)
movl %eax, 4(%esp)
movl $LC1, (%esp)
call _printf
movl $0, %eax
movl %eax, 24(%esp)
jmp L8
L5:
movl 36(%esp), %edx
movl 32(%esp), %eax
testl %eax, %eax
je L6
cmpl $1, %eax
je L7
.word 0x0b0f
L6:
movl %edx, %eax
movl %eax, (%esp)
movl $-1, 32(%esp)
call __Unwind_SjLj_Resume
L7:
movl %edx, %eax
movl %eax, (%esp)
movl $-1, 32(%esp)
call __Unwind_SjLj_Resume
L8:
leal 28(%esp), %eax
movl %eax, (%esp)
call __Unwind_SjLj_Unregister
movl 24(%esp), %eax
leal -12(%ebp), %esp
popl %ebx
popl %esi
popl %edi
popl %ebp
ret
.section .gcc_except_table,"w"
LLSDA959:
.byte 0xff
.byte 0xff
.byte 0x1
.uleb128 LLSDACSE959-LLSDACSB959
LLSDACSB959:
.uleb128 0
.uleb128 0
.uleb128 0x1
.uleb128 0
LLSDACSE959:
.text
.section .rdata,"dr"
.align 4
LC2:
.ascii "hello ....\316\322\312\307\304\243\260\345\272\257\312\375 \273\266\323\255 calll \316\322\0"
.section .text$_Z6myswapIiEvRT_S1_,"x"
.linkonce discard
.globl __Z6myswapIiEvRT_S1_
.def __Z6myswapIiEvRT_S1_; .scl 2; .type 32; .endef
<span style="color:#ff0000;">__Z6myswapIiEvRT_S1_: // 117</span>
pushl %ebp
movl %esp, %ebp
subl $40, %esp
movl $0, -12(%ebp)
movl 8(%ebp), %eax
movl (%eax), %eax
movl %eax, -12(%ebp)
movl 12(%ebp), %eax
movl (%eax), %edx
movl 8(%ebp), %eax
movl %edx, (%eax)
movl 12(%ebp), %eax
movl -12(%ebp), %edx
movl %edx, (%eax)
movl $LC2, 4(%esp)
movl $__ZSt4cout, (%esp)
call __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
movl $__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, (%esp)
movl %eax, %ecx
call __ZNSolsEPFRSoS_E
subl $4, %esp
leave
ret
.section .text$_Z6myswapIcEvRT_S1_,"x"
.linkonce discard
.globl __Z6myswapIcEvRT_S1_
.def __Z6myswapIcEvRT_S1_; .scl 2; .type 32; .endef
<span style="color:#ff0000;">__Z6myswapIcEvRT_S1_: // 145</span>
pushl %ebp
movl %esp, %ebp
subl $40, %esp
movb $0, -9(%ebp)
movl 8(%ebp), %eax
movb (%eax), %al
movb %al, -9(%ebp)
movl 12(%ebp), %eax
movb (%eax), %dl
movl 8(%ebp), %eax
movb %dl, (%eax)
movl 12(%ebp), %eax
movb -9(%ebp), %dl
movb %dl, (%eax)
movl $LC2, 4(%esp)
movl $__ZSt4cout, (%esp)
call __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
movl $__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, (%esp)
movl %eax, %ecx
call __ZNSolsEPFRSoS_E
subl $4, %esp
leave
ret
.text
.def ___tcf_0; .scl 3; .type 32; .endef
___tcf_0:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
movl $__ZStL8__ioinit, %ecx
call __ZNSt8ios_base4InitD1Ev
leave
ret
.def __Z41__static_initialization_and_destruction_0ii; .scl 3; .type 32; .endef
__Z41__static_initialization_and_destruction_0ii:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
cmpl $1, 8(%ebp)
jne L12
cmpl $65535, 12(%ebp)
jne L12
movl $__ZStL8__ioinit, %ecx
call __ZNSt8ios_base4InitC1Ev
movl $___tcf_0, (%esp)
call _atexit
L12:
leave
ret
.def __GLOBAL__sub_I_main; .scl 3; .type 32; .endef
__GLOBAL__sub_I_main:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
movl $65535, 4(%esp)
movl $1, (%esp)
call __Z41__static_initialization_and_destruction_0ii
leave
ret
.section .ctors,"w"
.align 4
.long __GLOBAL__sub_I_main
.def __Unwind_SjLj_Resume; .scl 2; .type 32; .endef
.def _printf; .scl 2; .type 32; .endef
.def __ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_; .scl 2; .type 32; .endef
.def __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc; .scl 2; .type 32; .endef
.def __ZNSolsEPFRSoS_E; .scl 2; .type 32; .endef
.def __ZNSt8ios_base4InitD1Ev; .scl 2; .type 32; .endef
.def __ZNSt8ios_base4InitC1Ev; .scl 2; .type 32; .endef
.def _atexit; .scl 2; .type 32; .endef

观察发现一个现象,myswap函数模版有一个声明,两个定义,这样的情况和我在“为什么会有函数模版中”博文中提到的两个myswap函数非常相似,实际这里体现了C++实现函数模版的本。本来须要程序猿依据须要去写非常多个逻辑同样,參数不同的函数。可是C++编译器帮我们做了这件事,依据调用会自己主动生成这些函数。这也是为什么函数模版能够和普通函数放在一起。

总结:函数模版机制结论:

编译器并非把函数模版处理成可以处理随意类的函数;

编译器从函数模版通过详细类型产生不同的函数;

编译器会对函数模版进行两次编译:在声明的地方对模版代码本身进行编译,在调用的地方对參数替换后的代码进行编译。

C++编译器函数模版机制剖析 - 函数模版的本质的更多相关文章

  1. Web API 处理机制剖析 --- 拨开迷雾看本质

     前言 最近开发了几个项目,用到了web api,也通过项目加深了对web api的理解.本文试图从内部原理讲解web api的本质.透过重重迷雾,看清本质,就能更好的把握和利用好web api. 1 ...

  2. C++中函数模版和普通函数的区别

    函数模版和同名普通函数在同一个作用域中,会优先调用那个函数? 函数模型在进行调用的时候会进行严格的类型匹配,而普通函数在调用的时候,会进行函数参数类型转换(前提是自动类型转换). 调用函数模版,本质是 ...

  3. C++ 类模板二(类模版与友元函数)

    //类模版与友元函数 #include<iostream> using namespace std; template<typename T> class Complex{ p ...

  4. malloc 函数工作机制(转)

    malloc()工作机制 malloc函数的实质体现在,它有一个将可用的内存块连接为一个长长的列表的所谓空闲链表.调用malloc函数时,它沿连接表寻找一个大到足以满足用户请求所需要的内存块.然后,将 ...

  5. C++编译器模板机制剖析

    思考:为什么函数模板可以和函数重载放在一块.C++编译器是如何提供函数模板机制的? 一.编译器编译原理 什么是gcc gcc(GNU C Compiler)编译器的作者是Richard Stallma ...

  6. Python 函数参数传递机制.

    learning python,5e中讲到.Python的函数参数传递机制是对象引用. Arguments are passed by assignment (object reference). I ...

  7. day11(函数参数,函数对象,打散机制,函数嵌套调用)

    一,复习 # 什么是函数:具体特定功能的代码块 - 特定功能代码块作为一个整体,并给该整体命名,就是函数 # 函数的优点: # 1.减少代码的冗余 # 2.结构清晰,可读性强 # 3.具有复用性,开发 ...

  8. 多线程中的信号机制--signwait()函数【转】

    本文转载自:http://blog.csdn.net/yusiguyuan/article/details/14237277 在Linux的多线程中使用信号机制,与在进程中使用信号机制有着根本的区别, ...

  9. Mqtt paho 回调函数触发机制跟踪

    Python Mqtt paho 回调函数触发机制跟踪,我使用的是 buildroot 里面的 mqtt paho , 代码在 ''' buildroot-2017.02.8/output/build ...

随机推荐

  1. 1880-A. 偷吃可耻

    描述 EATER买来一堆好吃的,总共N+1份,共(N+1)/2种,每种准备了两份,同种都标上了相同的编号.本来准备与他家吃货一同分享,结果却发现被人偷吃了..EATER发现总数少了一个,所以你的任务就 ...

  2. php访问类静态属性

    在类的外部,如果要使用到类的静态变量,则可以使用 :: 操作符. <?php class A { static $x = 10; function test() { echo self::$x; ...

  3. cat命令常用的13个技巧

    在Linux系统中,大多数配置文件.日志文件,甚至shell脚本都使用文本文件格式,因此,Linux系统存在着多种文本编辑器,但当你仅仅想要查看一下这些文件的内容时,可使用一个简单的命令-cat. c ...

  4. SPRING IN ACTION 第4版笔记-第四章ASPECT-ORIENTED SPRING-010-Introduction为类增加新方法@DeclareParents、<aop:declare-parents>

    一. 1.Introduction的作用是给类动态的增加方法 When Spring discovers a bean annotated with @Aspect , it will automat ...

  5. file_operations结构2

    对与应用层的每个系统调用,驱动程序都有一个与之对应的函数.对于字符设备驱动程序,这些函数集合在一个file_operations类型的数据结构中,该结构体在Linux内核的include/linux/ ...

  6. poj1691(dfs)

    链接 dfs了 写得有点乱 #include <iostream> #include<cstdio> #include<cstring> #include<a ...

  7. 代码重构的技巧——合理使用@Deprecated

    最近由于工作环境不太理想,很长时间没心情写技术博文,今天在调试springMVC的DispatcherSevlet类的代码时,看到一处代码且联想到项目中程序员的一些做法,觉得有必要写一下. 我们在做项 ...

  8. jQuery on()方法绑定动态元素的点击事件

    之前就一直受这个问题的困扰,在jQuery1.7版本之后添加了on方法,之前就了解过,其优越性高于live(),bind(),delegate()等方法,在此之前项目中想用这个来测试结果发现,居然动态 ...

  9. 谈谈分布式事务之二:基于DTC的分布式事务管理模型[下篇]

    [续上篇] 当基于LTM或者KTM的事务提升到基于DTC的分布式事务后,DTC成为了本机所有事务型资源管理器的管理者:此外,当一个事务型操作超出了本机的范 围,出现了跨机器的调用后,本机的DTC需要于 ...

  10. Tdxtreelist 行变色

    ACanvas.Font.Color := clRed;   //如果有加印的  变颜色