据我了解,您最关心构建时间和库的可维护性?
首先,不要试图一次“修复”所有问题。
其次,了解您要解决的问题。模板的复杂性通常是有原因的,例如强制某些用途,并使编译器帮助您不犯错误。这个原因有时可能会被认为很远,但是不应该掉以轻心,因为“没有人真正知道他们在做什么”而抛出 100 行。我在这里建议的所有内容都可能引入非常讨厌的错误,您已被警告过。
第三,首先考虑更便宜的修复:例如更快的机器或分布式构建工具。至少,把板子占用的所有内存都扔进去,扔掉旧磁盘。它确实有所作为。一个用于操作系统的驱动器,一个用于构建的驱动器是廉价的人 RAID。
图书馆是否有据可查?那是你制作它的最佳机会。查看诸如 doxygen 之类的工具来帮助你创建这样的文档。
都考虑了?好的,现在对构建时间提出一些建议;)
了解 C++构建模型:每个 .cpp 都是单独编译的。这意味着许多带有许多标头的 .cpp 文件 = 巨大的构建。不过,这并不是将所有内容都放入一个 .cpp 文件的建议!但是,可以极大地加快构建速度的一个技巧(!)是创建一个包含一堆 .cpp 文件的单个 .cpp 文件,并且只将该“主”文件提供给编译器。但是,您不能盲目地这样做——您需要了解这可能引入的错误类型。
如果您还没有,请获得一台可以远程访问的单独构建机器。你必须做很多几乎完整的构建来检查你是否破坏了一些包含。您将希望在另一台机器上运行它,这不会阻止您从事其他工作。从长远来看,无论如何您都需要它来进行日常集成构建;)
使用预编译头文件。(使用快速机器可以更好地扩展,见上文)
检查您的标头包含政策。虽然每个文件都应该是“独立的”(即包含它需要被其他人包含的所有内容),但不要随意包含。不幸的是,我还没有找到一个工具来查找不必要的#incldue 语句,但花一些时间删除“热点”文件中未使用的标题可能会有所帮助。
为您使用的模板创建和使用前向声明。通常,您可以在许多地方包含带有前向声明的标题,而仅在少数特定的地方使用完整的标题。这可以极大地帮助编译时间。检查<iosfwd>
标头标准库如何为 i/o 流执行此操作。
少数类型的模板重载:如果您有一个仅对少数类型有用的复杂函数模板,如下所示:
// .h
template <typename FLOAT> // float or double only
FLOAT CalcIt(int len, FLOAT * values) { ... }
您可以在标头中声明重载,并将模板移动到正文:
// .h
float CalcIt(int len, float * values);
double CalcIt(int len, double * values);
// .cpp
template <typename FLOAT> // float or double only
FLOAT CalcItT(int len, FLOAT * values) { ... }
float CalcIt(int len, float * values) { return CalcItT(len, values); }
double CalcIt(int len, double * values) { return CalcItT(len, values); }
这会将冗长的模板移动到单个编译单元。
不幸的是,这仅对类有有限的用途。
检查PIMPL 习语是否可以将代码从标头移动到 .cpp 文件中。
隐藏在它后面的一般规则是将库的接口与实现分开。使用注释、detail
命名空间和单独.impl.h
的标题在精神上和物理上将外部应该知道的内容与其完成方式隔离开来。这暴露了您的库的真正价值(它实际上封装了复杂性吗?),并让您有机会首先替换“简单目标”。
更具体的建议——以及给出的建议有多有用——很大程度上取决于实际的图书馆。
祝你好运!