在下面的代码中,我创建了一个 Builder
模板,并提供了一个默认实现以不返回任何内容。然后我使用 int 专门化模板,以返回值 37。
当我使用-O0
编译时,代码打印37,这是预期的结果。但是当我使用 -O3
编译时,代码打印 0。
平台是Ubuntu 20.04,GCC 9.3.0
任何人都可以帮助我理解这种行为吗?
builder.h
class Builder {
public:
template<typename C>
static C build() {
return 0;
}
};
builder.cc
#include "builder.h"
template<>
int Builder::build<int>() {
return 37;
}
main.cc
#include "builder.h"
#include <iostream>
int main() {
std::cout << Builder::build<int>() << '\n';
}
生成文件
CXX_FLAG = -O0 -g
all:
g++ $(CXX_FLAG) builder.cc -c -o builder.o
g++ $(CXX_FLAG) main.cc builder.o -o main
clean:
rm *.o
rm main
最佳答案
您应该为 build<int>()
添加前向声明至builder.h
,像这样:
template<>
int Builder::build<int>();
否则,编译时main.cc
,编译器只能看到通用模板,并且允许内联通用 build()
的实例。功能。如果您添加前向声明,编译器就会知道您在其他地方提供了专门化,并且不会内联它。
与 -O3
,编译器尝试内联,使用 -O0
它不会内联任何内容,因此存在差异。
您的代码实际上违反了 "One Definition Rule" :它将为 Builder::build<int>()
创建两个定义,但它们并不相同。标准称结果未定义,但不需要诊断。在这种情况下有点不幸,因为如果生成警告或错误消息会很有帮助。
关于C++:模板特化导致调试/发布中的不同结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65876360/