假设相当大的模板图书馆大约有100的文件含有约100个模板与总体超过200,000行代码。一些模板的使用多个继承使用的图书馆本身,而不是简单的(即继承一些基本的模板,并且只具有执行某些业务的规则)。

所有存在(增长了数年),"工程"和被用于项目。

然而,汇编的项目使用,图书馆需要消耗大量的时间和需要相当长的一段时间,以找到源于某些错误。固定往往引起意外副作用,或是相当困难的,因为有些相互依赖的模板需要改变。测试是几乎不可能由于大量的功能。

现在,我真的很喜欢简化的架构,以较少使用的模板和更专门的小类。

是否有任何证明方式去这任务吗?是什么将是一个很好的地方开始?

有帮助吗?

解决方案

我不知道我怎么看/为什么模板是问题,为什么普通的非模板类将是一个进步。这难道不只是意味着即使的更多的班,少的类型安全等更大的潜在错误?

我可以理解简化架构,重构和各种类和模板之间去除的依赖关系,但是自动假设“较少的模板将使架构更好”的伊莫有缺陷的。

我想说的是模板的可能的允许你建立一个更清洁架构比你没有他们得到的。很简单,因为你可以使单独的类的完全的独立。如果没有模板,调入另一个类的类函数必须了解类,或者它继承,提前一个接口。使用模板,这种耦合是没有必要的。

拆卸模板只会导致更多依赖关系,而不是更少。 模板添加的类型安全性,可以用来检测了很多在编译时错误的(有static_assert的用于此目的的慷慨洒你的代码)

当然,增加的编译时间可能是一个有效的理由,以避免在某些情况下的模板,如果你只是有一堆Java程序员,谁是用来在“传统” OOP思维的,模板可能会混淆它们,其可以是另一种有效的理由,避免模板。

但从架构点,我想避免模板是在错误的方向的步骤。

重构应用程序,当然,这听起来像是一个需要。但不要扔掉的最有用的工具之一,用于生产,只是因为该应用程序的原始版本滥用它的可扩展和可靠的代码。特别是,如果你已经关注的代码量,去除模板将最有可能导致的更多的行代码。

其他提示

您需要的自动化测试,在十周几年的时间这样一来当你的succesor有他可以重构代码相同的问题(可能增加,因为他认为这将简化库的使用更多的模板),并知道它仍然满足所有测试案例。相似地,任何轻微的错误修复的副作用将是立即可见(假设测试用例是好的)。

除此之外, “分而conqueor”

写入单元测试。

其中新的代码必须执行与旧代码。

这是一个尖的至少

编辑:

如果您弃用您已经用新的功能替换旧的代码你 可以通过小相转移到新的代码少。

好了,问题是这种思维方式的模板是面向对象的基于继承的方式非常不同。这是很难回答别的比“重新设计了整个事情,从头开始。”

当然,也可以是用于特定情况下的简单方式。我们不能说没有更多地了解你所拥有的。

,模板溶液是如此难以保持,这一事实是一个设计不良的指示反正。

一些要点(但请注意:这些都是 邪恶的。如果你想改变的非模板代码,不过,这可以帮助推):


查找你的静态界面.在哪里做模板,取决于什么样的功能存在?如果这样做,他们需要typedef?

把共同的部分,在一个抽象的基类。一个很好的例子就是当你发生绊倒的CRTP成语。你可以替代它与一个抽象的基类具有虚拟的功能。

查找整数列.如果你找到你的代码使用的整体清单喜欢 list<1, 3, 3, 1, 3>, 你可以替代他们 std::vector, 如果所有代码使用他们可以生活与工作与运行时间值,而不是恒的表达。

查找特征的类型.有多少代码中涉及检查是否有一些typedef存在,或是否有些方法中存在的典型模板的代码。抽象baseclasses解决这两个问题通过使用纯粹的虚拟方法,通过继承typedef的基础。通常,typedef只需要扳机的丑恶特征喜欢 SFINAE, ,那么这将是多余的了。

查表的模板.如果你的代码使用的表达的模板,以避免创造临时的你会必须消除他们使用传统的方式返回/递临时的营运商的参与。

查找功能的对象.如果你找到你的代码使用功能物体,则可以改变他们使用抽象的基类也有喜欢的东西 void run(); 给他们打电话(或者如果你想继续使用 operator(), ,更好的是这样!它可以是虚拟的太)。

据我了解,你最关心的生成时间,和你的库的可维护性?

首先,不要试图“修复”的一次。

二,了解你解决什么。模板复杂性常常是有原因的,例如实施某些使用,使编译器帮助你,不是犯了一个错误。因此有时会被带到远,但投出100行,因为“没有人真的知道他们做了什么”不应该掉以轻心。一切,我认为在这里可以介绍真正讨厌的错误,你已经被警告。

三,首先考虑更便宜的解决方法:例如更快的机器或分布式的构建工具。至少,扔在所有的RAM板将采取和抛弃旧盘。它迈科的差异。一个驱动器的操作系统,一个驱动器,用于构建是一种廉价芒RAID。

时的图书馆有据可查?这是在使它看起来成如doxygen的工具,帮助您创建这样的文件你最好的机会。

所有考虑?行,现在一些建议的生成时间;)


了解C ++的 建立模型 :每次的.cpp单独编译。这意味着许多许多头.cpp文件=巨大的构建。这不是把一切都变成一个.cpp文件,虽然一个提醒!然而,一招(!),可以加快构建非常是创建一个包含了一堆的.cpp文件一个.cpp文件,并只喂的是“大师”的文件编译器。你不能做到这一点盲目,但是 - 你需要了解的错误类型,这可能推出的

如果你没有一个呢,获取一个单独的构建机器,你可以远程进入。你必须做很多的几乎完全建立检查,如果你打破了一些包括。你会想在另一台机器,不从做别的事情阻止你运行此。从长远来看,你会每天集成构建反正需要它;)

使用的预编译的头即可。 (鳞片与快速机器更好,见上文)

检查你的头列入政策即可。虽然每个文件应该是“独立”(即包括一切,它需要由其他人包括在内),不包括宽松。不幸的是,我还没有找到一个工具来查找不必要#incldue语句,但它可能会帮助花一些时间去除“热点”文件未使用的标题。

创建并使用前置声明作为您使用的模板。通常情况下,你可以用incldue声明forwad头在许多地方,只有在少数特定的人使用的完整标题。这可以极大地帮助编译时间。检查<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 namesapces和独立.impl.h头到身心分离又该它是如何实现的可知道外面的。这暴露了你的图书馆(它实际上封装复杂?)的实际价值,并给你一个机会,以取代“容易的目标”之首。


更具体的提醒 - 怎么有用给出的是 - 德暂时搁置很大程度上实际库。

祝你好运!

如前所述,单元测试是一个好主意。事实上,而不是通过引入“简单”的变化有可能会蔓延破坏你的代码,只需专注于创建一套测试,和固定不遵守测试。有一个活动时的错误来光来更新测试。

除此之外,我建议升级工具,如果可能的话,以帮助调试模板相关的问题。

我经常会遇到是巨大的,并需要大量的时间和内存实例,但也没必要将传统的模板。在这种情况下,削减了脂肪的最简单的方法就是把所有没有依靠任何的模板参数,并把它隐藏在一个正常的转换单元中定义不同的功能代码。这也有当该代码必须被稍微修改或改变文档触发较少的重新编译的正副作用。这听起来相当明显,但它确实令人惊讶人们经常写一个类模板,并认为它所做的一切在标题中定义的,而不是仅仅需要的模板信息的代码。

您可能要考虑的另一件事是你如何往往通过使模板“混入”风格,而不是多重继承的集合的清理继承层次。看看有多少地方可以用制作的模板参数一个基类,它应该从(顺便boost::enable_shared_from_this作品)获得的名称脱身。当然,这通常只运作良好,如果构造函数没有参数,因为你不必担心正确初始化任何东西。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top