假设我有一个5000行,深度嵌套的函数,我想将一个1000行的块提取到一个新函数中。
在Java和C#中,我可以让ReSharper,IntelliJ和Visual C#处理安全提取方法所需的分析,无论代码有多长和多长。我可以确信他们不会改变代码的行为,即使这对我的小脑子来说太难理解了。
可用的C ++工具无法给予我相同的信心。 CLion,ReSharper和Visual Assist都会在提取方法时引入行为更改。
我有什么选择?
答案 0 :(得分:6)
一种选择是根据Tennent的通信原则使用此配方。您可以将它应用于整个块(由大括号括起)或if
,while
或for
语句(创建自己的范围)。
围绕块包围:
[&]() {
// original code
}();
编译文件。可能的错误:
并非所有控制路径都会返回值。您可以提早返回。备份并消除早期返回/继续/中断或提取不同的内容。
中断/继续声明只能在...内使用您有休息/继续。备份并消除早期返回/继续/中断或提取不同的内容。
检查新的lambda是否有任何return语句。如果有任何返回,并且很明显所有代码路径都返回,那么在lambda之后的下一行添加一个return语句。如果有任何返回并且所有代码路径都返回并不明显,则备份并消除早期返回/继续/中断或尝试提取不同的内容。
即
[&]() {
// ...
}();
变为:
auto Applesauce = [&]() {
// ...
};
Applesauce();
编译以确保您没有输入错误。
在lambda上设置返回类型(即使它是void
)。在Visual Studio中,auto
上的工具提示会告诉您类型。
即:
auto Applesauce = [&]() -> SOMETYPE {
// ...
};
编译以确保返回类型正确。
将[&]
替换为[this]
(或免费功能中的[]
)并进行编译。
对于必须捕获的变量的每个错误:
- 复制变量名称
- 将其粘贴到捕获列表中,前缀为&
- 重复直到绿色。
即:
auto Applesauce = [this, &foo]() -> void {
cout << foo;
};
捕获列表的顺序将影响最终函数的参数顺序。如果您希望按特定顺序排列参数,现在是重新排序捕获列表的好时机。
对于每个捕获的局部变量(this
除外)
- 转到变量的定义
- 复制变量声明(例如Column* pCol
)
- 粘贴到lambda参数列表中
- 使参数const和by-reference
- 从捕获列表中删除变量
- 将变量传递给呼叫
- 编译。
即:
Column* pCol = ...
auto Applesauce = [&pCol]() -> void { cout << pCol->name(); };
Applesauce();
变为
Column* pCol = ...
auto Applesauce = [](Column*& pCol) -> void { cout << pCol->name(); };
Applesauce(pCol);
如果捕获this
,请使用6A。
如果未捕获this
,请使用6B。
= [this]
SomeClass::
即:
auto SomeClass::Applesauce () const -> void {
// ...
};
= []