我注意到如果启用编译器优化,.cpp文件中的模板特化将被丢弃。我在一个大型应用程序中发现了这个问题,并将其简化为一个简单的示例。
首先,在obj.h中定义一个新类:
#ifndef _OBJ_H_
#define _OBJ_H_
class Obj { };
#endif //_OBJ_H_
然后我在templates.h中定义了一个新的模板函数。
#ifndef _TEMPLATES_H_
#define _TEMPLATES_H_
template<typename T>
int get()
{
return 0;
}
#endif //_TEMPLATES_H_
...在templates.cpp中针对类Obj的特化
#include "templates.h"
#include "obj.h"
template<>
int get<Obj>()
{
return 1;
}
然后我从主函数中调用该函数:
#include <stdio.h>
#include "templates.h"
#include "obj.h"
int main()
{
printf("Get: %d\n", get<Obj>());
return 0;
}
使用不同的
-O
级别编译此示例会产生不同的输出。$ g++ -o a main.cpp templates.cpp -O0
$ ./a
Get: 1
$ g++ -o a main.cpp templates.cpp -O2 #same with -O3, -O4, Os
$ ./a
Get: 0
使用clang替换g++也会发生同样的情况。我使用的是g++ 4.7.2和clang 3.4。
虽然我不是汇编专家,但通过查看生成的代码,我可以看到
-O0
版本定义了名为_Z3getI3ObjEiv
的符号,它引用了特化模板,而优化版本则将所有内容都内联了(正如我所预期的那样)。问题最终是通过将所有特化模板移到头文件中解决的,但我仍然很好奇:为什么会发生这种情况?起初我认为我遇到了未定义的行为,尽管如果是这种情况,clang和g++产生相同的结果就有些奇怪了。