如何确认编译器是否使用多库中的模板显式实例化而非隐式实例化?
问题背景
现有包含模板实现的头文件FooHeader.hpp:
#ifndef FOOHEADER_HPP #define FOOHEADER_HPP template <typename T> struct Foo { void FooFun(){} }; #endif
另有两个.cpp文件提供该模板的显式实例化:FloatFoo.cpp:
#include "FooHeader.hpp" template struct Foo<float>;
IntFoo.cpp:
#include "FooHeader.hpp" template struct Foo<int>;
将这两个.cpp文件编译为动态库IntFoo.so和FloatFoo.so,并在main.cpp中使用这些模板实例:
#include "FooHeader.hpp" int main() { Foo<float> foo; Foo<int> iFoo; iFoo.FooFun(); foo.FooFun(); }
编译命令为:
clang++ main.cpp -L./ -lIntFoo -lFloatFoo
请问如何确认编译器实际使用的是IntFoo、FloatFoo库中的显式实例化代码,还是在main.cpp中隐式实例化的新代码?
验证方法
方法1:通过修改动态库实现验证行为差异
因为原头文件中FooFun是内联实现,编译器可能直接内联代码导致无法区分,先调整代码结构:
- 修改
FooHeader.hpp,分离声明与实现:#ifndef FOOHEADER_HPP #define FOOHEADER_HPP template <typename T> struct Foo { void FooFun(); }; #endif - 在
FloatFoo.cpp中添加独特实现:#include "FooHeader.hpp" #include <cstdio> template <> void Foo<float>::FooFun() { printf("From FloatFoo.so\n"); } template struct Foo<float>; - 在
IntFoo.cpp中添加对应实现:#include "FooHeader.hpp" #include <cstdio> template <> void Foo<int>::FooFun() { printf("From IntFoo.so\n"); } template struct Foo<int>; - 重新编译动态库与可执行文件,运行后若打印出对应字符串,说明使用的是动态库中的显式实例;若无对应输出,则是在
main.cpp中隐式实例化的代码。
方法2:查看符号依赖与符号表
- 用
nm命令查看可执行文件的符号:
若符号标记为nm -D ./a.out | grep FooFunU(未定义),说明运行时会从动态库加载;若标记为T(文本段,已定义),则是在main.cpp中隐式实例化的代码。 - 结合
objdump查看动态库中的符号:
对比可执行文件的符号表,若可执行文件的objdump -T ./IntFoo.so | grep FooFunFooFun<int>/FooFun<float>符号指向动态库中的对应符号,说明使用的是库中的实例。
方法3:编译时禁用隐式实例化
编译main.cpp时添加-fno-implicit-templates参数,禁止编译器自动隐式实例化模板:
clang++ main.cpp -L./ -lIntFoo -lFloatFoo -fno-implicit-templates
- 若编译成功,说明编译器找到了动态库中的显式实例;
- 若编译失败并报
undefined reference错误,说明原本编译器会在main.cpp中隐式实例化,证明之前使用的是隐式实例化的代码。
方法4:查看编译中间汇编文件
编译main.cpp时生成汇编代码:
clang++ -S main.cpp -o main.s
查看main.s文件:
- 若文件中包含
FooFun<int>或FooFun<float>的汇编实现代码,说明是隐式实例化; - 若只有对这些函数的调用指令(无实现代码),说明是调用动态库中的显式实例。
内容的提问来源于stack exchange,提问作者Anon232
相关产品推荐
相关产品推荐

