关于代码膨胀,我认为罪魁祸首可能是内联而不是模板。
例如:
// foo.h
template <typename T> void foo () { /* some relatively large definition */ }
// b1.cc
#include "foo.h"
void b1 () { foo<int> (); }
// b2.cc
#include "foo.h"
void b2 () { foo<int> (); }
// b3.cc
#include "foo.h"
void b3 () { foo<int> (); }
链接器很可能会将“foo”的所有定义合并到一个翻译单元中。因此 'foo' 的大小与任何其他命名空间函数的大小没有什么不同。
如果您的链接器不这样做,那么您可以使用显式实例化来为您执行此操作:
// foo.h
template <typename T> void foo ();
// foo.cc
#include "foo.h"
template <typename T> void foo () { /* some relatively large definition */ }
template void foo<int> (); // Definition of 'foo<int>' only in this TU
// b1.cc
#include "foo.h"
void b1 () { foo<int> (); }
// b2.cc
#include "foo.h"
void b2 () { foo<int> (); }
// b3.cc
#include "foo.h"
void b3 () { foo<int> (); }
现在考虑以下几点:
// foo.h
inline void foo () { /* some relatively large definition */ }
// b1.cc
#include "foo.h"
void b1 () { foo (); }
// b2.cc
#include "foo.h"
void b2 () { foo (); }
// b3.cc
#include "foo.h"
void b3 () { foo (); }
如果编译器决定为您内联“foo”,那么您最终将得到 3 个不同的“foo”副本。看不到模板!
编辑:来自 InSciTek Jeff 的上述评论
对你知道只会使用的函数使用显式实例化,你还可以确保删除所有未使用的函数(与非模板情况相比,这实际上可以减少代码大小):
// a.h
template <typename T>
class A
{
public:
void f1(); // will be called
void f2(); // will be called
void f3(); // is never called
}
// a.cc
#include "a.h"
template <typename T>
void A<T>::f1 () { /* ... */ }
template <typename T>
void A<T>::f2 () { /* ... */ }
template <typename T>
void A<T>::f3 () { /* ... */ }
template void A<int>::f1 ();
template void A<int>::f2 ();
除非您的工具链完全中断,否则上述代码只会为“f1”和“f2”生成代码。