在我正在开发的应用程序中,我有一个像这样的模板函数:
template<class T>
void CIO::writeln(T item)
{
stringstream ss;
ss << item << '\r' << endl;
write(ss.str());
}
从多个地方调用此函数,T = const char *和T = std :: string。使用CodeSourcery Lite 2008.03-41(GCC 4.3.2),使用-O3编译器标志编译和链接。但是,由于我更改为CodeSourcery Lite 2012.03-57(GCC 4.6.3),使用-O3进行编译是正常的,但随后链接将失败并显示undefined reference to void CIO::writeln<std::string>(std::string)
。使用-O2或更低时,一切正常,链接成功。
我对此进行了深入研究,并在程序集输出中发现了一些奇怪的东西:使用-O2编译时,我可以找到函数的两个特化:一个用于const char *(_ZN3CIO7writelnIPKcEEvT_
),另一个用于std :: string(_ZN3CIO7writelnISsEEvT_
),但在使用-O3进行编译时,缺少第二个特化,这解释了链接错误。
这是编译器错误吗?这个奇怪的优化变成了邪恶吗?
提前致谢!
编辑:此功能位于源文件中。在Mike Seymour的评论之后,我把它移到标题上,现在一切都很好。我承认我应该早点意识到这一点。尽管如此,根据优化标志,仍然会检查是否检查语言规则。
答案 0 :(得分:1)
与其他答案不同,这可能不是编译器错误。
-O3
启用的优化之一是函数内联。我认为发生的事情是:
源文件1在没有定义的情况下调用CIO::writeln
。它被编译为目标文件1.
源文件2在定义可用时调用CIO::writeln
。它被编译为目标文件2.
目标文件1仅在目标文件2包含CIO::writeln
的定义时才可用。如果源文件2中的调用被内联,则对象文件2将不包含它的定义。如果没有内联调用,则可以使用定义。
注释中给出的解决方案将定义移动到头文件中是正确的。