赞
踩
为了方便维护,我们一般将函数声明放在 .h 文件,将函数定义放在 .c 或者 .cpp 文件。但是 函数模板是无法将声明和定义放在两个文件的,最直接的理由是函数模板因为没有被实例化,编译器不会编译函数模板。
目录
假设函数模板的声明、定义和调用的位置如下:
程序运行分为四个阶段我们下面就从这四个阶段分析。我们主要看两个cpp文件,因为h文件在第一阶段就被展开了。
这个阶段的作用主要是头文件展开、宏替换、去掉注释。main.cpp文件、Add.cpp文件可以看作是下面的情况,最终会生成 main.i、Add.i文件。
这个阶段的主要作用是语法分析、词法分析、符号汇总等,如果没有问题,则编译生成汇编代码。值得注意的是,函数模板在这里不会被编译。因为编译器根本就不知道Add函数的返回值要占用多大空间。
因此,Add.s 中不会出现 Add函数的相关实现,也就不存在对应的函数地址。
这个阶段主要是用上一个阶段汇总的符号(函数名、全局变量等),生成对应的符号表,因为我们实际链接的时候,假如要调用某个函数,起始就是根据符号表去找到对应的函数地址,然后再去执行对应的函数。
注意:Add对应的一栏里填写的 “ ? ” 只是临时的,因为在main函数所在源文件中没有找到Add函数的定义,也就没有对应的函数地址。
这个阶段是上述 .o 文件的交互阶段,此时编译器会把所有的 符号表合并,这样的话就构成了一张完整的表格。只不过Add.o 对应的符号表是空的,那么最终的符号表就是
编译器在链接Add函数的时候发现,Add函数没有对应的地址,找不到Add函数,这个时候就会报如下错误,无法解析的外部符号。
现在问题主要在于,将函数模板的定义单独放在一个文件的时候,编译器不会编译函数模板。
何时会编译Add函数? ==》Add函数模板实例化的时候 ==》 Add函数被调用的时候
也就是说,我们只要把函数模板的定义放在Add函数被调用的地方就可以了。之前在了解模板实例化的时候有这么一个图,当函数模板实例化的时候,此时编译器会生成实实在在的函数。此时编译器就可以在第二阶段编译函数生成对应的汇编代码,然后在第三阶段生成 Add函数的符号表了。
具体操作如下:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。