【发布时间】:2013-01-14 13:33:50
【问题描述】:
在我正在处理的项目的一些序列化代码中,我有一个类型,其大小取决于编译器。为了解决这个问题,我决定使用模板专业化,效果很好。一切都在编译时解决。代码看起来有点像这样(不是真正的代码,只是一个例子):
template <int size>
void
special_function()
{
std::cout << "Called without specialization: " << size << std::endl;
}
template <>
void
special_function<4>()
{
std::cout << "dword" << std::endl;
}
template <>
void
special_function<8>()
{
std::cout << "qword" << std::endl;
}
int
main()
{
special_function<sizeof(int)>();
return 0;
}
在我的 32 位系统上,按预期执行上述程序输出 dword。但是这样做而不只是if (sizeof(int) == 4) { ... } else if ... 这样做的全部意义在于,我希望编译器只会为适当的函数生成代码。由于special_function<4> 是该程序中唯一调用的一个,我希望它是编译器生成的唯一一个(在本例中为 gcc 4.1.2,在 x86 Linux 上)。
但这不是观察到的行为。
虽然它确实有效,但每个模板特化的代码都会生成,尽管从未使用过。但是,不会生成通用定义。
我应该提一下,这是一步编译,而不是编译成中间目标文件,然后是链接。在这种情况下,将死代码删除推迟到链接阶段似乎很自然,而且我知道链接器并不总是非常擅长这一点。
有人知道发生了什么吗?我在这里缺少模板专业化的微妙之处吗?天知道 C++ 的细节是魔鬼。
编辑:既然已经提到,这种行为发生在 -O3 和 -Os 上。
EDIT2:下面的 Rob 建议将函数放在匿名命名空间中。这样做并使用任何级别的优化进行编译确实会删除死代码,这很好。但我很好奇,所以我尝试对以下程序做同样的事情:
namespace {
void foo() { std::cout << "Foo!" << std::endl; }
void bar() { std::cout << "Bar!" << std::endl; }
}
int
main()
{
foo();
return 0;
}
这里的想法是看看 Rob 的解决方案是否真的与模板专业化有关。事实证明,上述启用优化编译的代码从可执行文件中删除了未使用的bar() 定义。所以看起来虽然他的回答解决了我的直接问题,但它并没有解释为什么根本没有使用的模板特化被编译。
有没有人知道标准中的相关 sn-p 可以解释这一点?我一直认为模板只是在使用时生成的,但对于完全专业化来说可能并非如此......
【问题讨论】:
-
启用优化。编译器不会包含未使用的代码。这称为“死代码消除”。
-
只要编译器能确定它永远不会被调用,是的,优化会移除那些函数。
-
完全特化不再是模板,其行为更像普通函数。例如,在标题中使用时,它们必须是
inline。 -
弗拉德,垫子:我应该指定的,我在 -O3 和 -Os 上都尝试过。没有任何区别。我将进行编辑以澄清。
-
@808140:你如何验证未使用的专业化没有被淘汰?
标签: c++ templates g++ specialization