模板代码增加了二进制文件的大小。

8
经常有人说,带有大量模板的代码会导致输出的大小增加,但这是真的吗?
#include <iostream>

#if 0
void foo( const int &v)
{
    std::cout<<v<<std::endl;
}
#else
template< typename T >
void foo( const T &v)
{
    std::cout<<v<<std::endl;
}
#endif

int main ()
{
    foo(50);
}

上面的例子生成不同大小的输出(函数输出为6.19k,模板函数输出为6.16k)。为什么使用模板的版本更小?
如果有影响的话,我正在使用带有下一个选项“-O3 -Wextra -Wall -pedantic”的g ++ 4.6.1。我不确定其他编译器的输出是什么。

9
在这个简单的例子中,尺寸相对一致。尝试同样的例子,但模板需要扩展到几百种类型。 - Chad
就好像你为每个模板实例化的类型编写了一个新的类/函数一样。这就像你用不同的名称或其他方式创建了不同的函数一样。 - Seth Carnegie
3
另外,试试一个模板不是一行的例子。 - Nicol Bolas
@Chad 我知道这一点(每个专业化领域的规模都在增加),但这不是我所问的。 - BЈовић
可能是使用STL会显著增加占用空间吗?的重复问题。 - Martin York
1
@Chad:如果你要比较苹果和橙子,至少要比较相同数量的橙子。在编写正常代码时也是如此。现在你必须编写数百个版本的函数(可能需要大量复制和粘贴)。最终得到的可执行文件相同,不同之处在于源代码的大小增加了数百倍。 - Martin York
2个回答

8
也许是因为你的示例中 foo 具有外部链接,因此即使调用被内联,它也会被发射到你的可执行文件中。
对于模板,如果调用被内联,就没有理由发出一个隐式实例化的函数模板特化。
尝试将 foo 做成一个 inline 函数或将其变成 static。如果你想要发出函数模板特化,你需要显式实例化它。
#else
template< typename T >
void foo( const T &v)
{
    std::cout<<v<<std::endl;
}
template void foo(const int&);
#endif

通过这样做,我的措施可以确保非模板函数和函数模板版本的大小完全相同。


这是正确的。即使将其放入无名命名空间中,也会产生完全相同的输出。 - BЈовић

1
当我们说模板会生成更多的代码时,实际上意味着与其他形式的动态或静态多态性(如虚函数、函数指针、选择、函数重载等)相比,它们更大。
例如,假设你有一个非常大的类模板,在某些代码中只有一个地方区别于int和float。那么,一个天真的编译器将复制整个类和代码,并且最终需要两倍的空间(实际上并不是这样,但为了举例,让我们假设是这样)。如果您只重载了一个方法,那么只有该部分的代码会被复制。
这也会导致令人讨厌的副作用,即使编译时间更长,因为它必须计算两倍的代码量。
您必须记住的是,每次使用新类型用于模板代码时,整个代码都会以新类型重新生成,而其他方法可能只是简单地在此处和那里切换指针。

1
这是一个错误的比喻。如果您用普通代码替换模板代码,您仍然有两个版本的代码,一个版本用于整数,另一个版本用于浮点数。不同之处在于您有两倍的源代码。 - Martin York
看起来正确的解决方案是将那个函数变成一个模板函数。 - David Stone

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接