Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何最好地从模板混乱切换到干净的类体系结构(C+;+;)?_C++_Templates_Simplify - Fatal编程技术网

C++ 如何最好地从模板混乱切换到干净的类体系结构(C+;+;)?

C++ 如何最好地从模板混乱切换到干净的类体系结构(C+;+;)?,c++,templates,simplify,C++,Templates,Simplify,假设一个较大的模板库包含大约100个文件,其中包含大约100个模板,总代码超过200000行。一些模板使用多重继承使库本身的使用变得相当简单(即从一些基本模板继承,只需实现某些业务规则) 所有存在的(经过几年的发展),“工作”并用于项目 然而,使用该库编译项目会消耗越来越多的时间,并且需要相当长的时间才能找到某些bug的源代码。修复通常会导致意外的副作用或相当困难,因为一些相互依赖的模板需要更改。由于函数数量巨大,测试几乎是不可能的 现在,我真的想简化体系结构,使用更少的模板和更专业的更小的类

假设一个较大的模板库包含大约100个文件,其中包含大约100个模板,总代码超过200000行。一些模板使用多重继承使库本身的使用变得相当简单(即从一些基本模板继承,只需实现某些业务规则)

所有存在的(经过几年的发展),“工作”并用于项目

然而,使用该库编译项目会消耗越来越多的时间,并且需要相当长的时间才能找到某些bug的源代码。修复通常会导致意外的副作用或相当困难,因为一些相互依赖的模板需要更改。由于函数数量巨大,测试几乎是不可能的

现在,我真的想简化体系结构,使用更少的模板和更专业的更小的类


有没有什么行之有效的方法来完成这项任务?什么是一个好的起点?

好吧,问题是模板的思维方式与基于面向对象继承的思维方式非常不同。除了“重新设计整件事,从头开始”之外,很难回答其他任何问题

当然,对于特定的情况,可能有一种简单的方法。如果不知道你有什么,我们就说不出来


模板解决方案很难维护这一事实表明,不管怎么说,它的设计很糟糕。

问题是,模板的思维方式与基于对象继承的思维方式大不相同。除了“重新设计整件事,从头开始”之外,很难回答其他任何问题

当然,对于特定的情况,可能有一种简单的方法。如果不知道你有什么,我们就说不出来


模板解决方案很难维护这一事实表明,无论如何,它的设计很差。

你需要自动化测试,这样在十年后,当你的成功者遇到同样的问题时,他可以重构代码(可能是添加更多的模板,因为他认为这样可以简化库的使用)并且知道它仍然满足所有测试用例。类似地,任何小错误修复的副作用都将立即可见(假设您的测试用例是好的)


除此之外,“分而治之”

您需要自动化测试,这样在十年后,当您的成功者遇到同样的问题时,他可以重构代码(可能会添加更多模板,因为他认为这将简化库的使用),并且知道它仍然满足所有测试用例。类似地,任何小错误修复的副作用都将立即可见(假设您的测试用例是好的)

除此之外,“分而治之”编写单元测试

其中新代码必须与旧代码相同

这至少是一个提示

编辑:

如果您不推荐使用新功能替换的旧代码 可以逐步过渡到新代码。

编写单元测试

其中新代码必须与旧代码相同

这至少是一个提示

编辑:

如果您不推荐使用新功能替换的旧代码
可以逐步过渡到新代码。

如前所述,单元测试是一个好主意。事实上,与其通过引入“简单”的更改来破坏代码,还不如专注于创建一套测试,并修复与测试不一致的地方。当发现bug时,有一个活动来更新测试


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

如前所述,单元测试是一个好主意。事实上,与其通过引入“简单”的更改来破坏代码,还不如专注于创建一套测试,并修复与测试不一致的地方。当发现bug时,有一个活动来更新测试

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

一些要点(但请注意:这些并不是坏事。但是,如果您想更改为非模板代码,这会有所帮助):


查找静态界面。模板在哪里取决于存在哪些函数?他们在哪里需要typedef

将公共部分放在抽象基类中。一个很好的例子是,当您碰巧在CRTP习惯用法上绊倒时。您可以将其替换为具有虚拟函数的抽象基类

查找整数列表。如果您发现您的代码使用整数列表,如
list
,您可以将它们替换为
std::vector
,如果所有使用它们的代码都可以使用运行时值而不是常量表达式

查找类型特征。有很多代码需要检查是否存在某些typedef,或者在典型的模板化代码中是否存在某些方法。抽象基类通过使用纯虚方法和将typedef继承到基类来解决这两个问题。通常情况下,typedef只需要触发像SFINAE这样的可怕特性,这也是多余的

查找表达式模板。如果您的代码使用表达式模板来避免创建临时对象,则必须消除它们,并使用传统的方法将临时对象返回/传递给相关的运算符

查找函数对象。如果您发现您的代码使用函数对象,您可以将它们也更改为使用抽象基类,并使用类似于
void run()
调用它们(或者如果您想继续使用
操作符()
,最好这样!它也可以是虚拟的)。

一些要点(但注意:这些确实不是坏事。但是,如果您想更改为非模板代码,这可能会有所帮助):


查找您的静态接口// .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); }