4

在我正在开发的应用程序中,我有一个这样的模板函数:

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 的评论,我将其移至标题,现在一切正常。我承认我应该早点意识到这一点。尽管如此,根据优化标志检查或不检查语言规则仍然让我感到害怕。

4

1 回答 1

1

与其他答案所说的不同,这可能不是编译器错误。

启用的优化之一-O3是函数内联。我认为正在发生的是:

CIO::writeln源文件 1 在没有其定义可用的情况下调用。它被编译为目标文件 1。

CIO::writeln源文件 2在其定义可用时正在调用。它被编译为目标文件 2。

目标文件 1 仅在目标文件 2 包含CIO::writeln. 如果源文件 2 中的调用被内联,目标文件 2 将不包含它的定义。如果调用没有被内联,定义将可用。

评论中给出的解决方案,将定义移动到头文件,是正确的。

于 2013-11-12T12:40:14.700 回答