如何重构嵌套的for循环?
How to refactor nested for loop?
我有两个类似的功能。这两个函数都包含一个嵌套的 for
循环。我如何结合这两个功能来减少重复代码。
funcA
和 funcB
之间的唯一区别是 funcB
在循环中调用 func_2
。
下面两个函数。
void funcA()
{
for (int i = 0; i < size; i++)
{
for (int j = 0; j < size; j++)
{
func_1();
}
}
}
void funcB()
{
for (int i = 0; i < size; i++)
{
for (int j = 0; j < size; j++)
{
func_1();
func_2();
}
}
}
funcA 和 funcB 的唯一区别是 funcB 调用 func_2(); 然后使用标志来控制是否应该调用该方法
void funcC(bool shouldInvokeFunc2)
{
for(int i = 0; i < size; i++)
{
for(int j = 0; j < size; j++) {
func_1();
if(shouldInvokeFunc2) // use the flag
{
func_2();
}
}
}
}
你本可以使用 variadic templates.
template<class ... FuncTypes>
void funcAB(FuncTypes... Funcs)
{
for(int i = 0; i < size; ++i) {
for(int j = 0; j < size; ++j) {
(Funcs(), ...);
}
}
}
调用函数的方法如下。
funcAB(&func_1); // if you want to only call func_1
funcAB(&func_1, &func_2) // if you want both to be called
您可以编写一个接受函数作为参数的函数,但没有更多信息,这是我能给出的唯一示例:
#include <iostream>
constexpr int size = 1;
void func(void (*f)())
{
for(int i = 0; i < size; i++)
{
for(int j = 0; j < size; j++)
{
f();
}
}
}
void func_1(){ std::cout << "func_1" << std::endl; }
void func_2(){ std::cout << "func_2" << std::endl; }
void funcA()
{
func_1();
}
void funcB()
{
func_1();
func_2();
}
int main()
{
func(funcA);
func(funcB);
return 0;
}
也许可以创建一个带参数的函数,具体取决于该参数调用 func_2()
。您还可以为该参数指定一个默认值。
void funcA(bool callFunc2 = false) {
for(int i = 0; i < size; i++) {
for(int j = 0; j < size; j++) {
func_1();
if (callFunc2) {
func_2();
}
}
}
}
funcA()
将 运行 不调用 func_2()
并且 funcA(true)
将 运行 执行 func_2()
.
也许我有点过头了,但是嵌套循环没有明显的原因(func_1()
和 func_2()
都不依赖于 i
或 j
).传递可调用对象的直接方法如下:
template <typename F>
void func(F f) {
for (int i=0; i < size*size; ++i) f();
}
然后调用
func([](){ func_1(); });
func(&func_1); // passing function pointer works as well
或
func([](){ func_1(); func_2(); });
PS:当size*size
可以溢出或为负数时,嵌套循环和平面循环之间存在差异。尽管传递可调用对象与此正交。
您可以用一个 template function. It takes variadic arguments of functions, and each function will be called by the fold expression (Since c++17) 扩展替换它。
此外,使用 ranges::views::iota
(Since c++20) 您可以将两个 for
循环合并为一个。
类似如下:
#include <ranges> // std::views::iota
template<typename... Funcs>
void funcAB(Funcs&&... funcs)
{
for ([[maybe_unused]] int i : std::views::iota(0, size * size)) {
(funcs(), ...);
}
}
您将调用 funcAB
:
funcAB(func1); // for funcA() call
funcAB(func1, func2); // for funcB() call
(Live Demo)
除了其他帖子中提到的将实现作为函数参数传递的不同方式(例如通过 lambda 或函数指针)之外,您还可以考虑继承和覆盖来表达行为的重用:
struct Base {
int size = 2;
void loop() {
for(int i = 0; i < size; i++) {
for(int j = 0; j < size; j++) {
func();
}
}
}
virtual void func() = 0;
};
struct A : public Base {
void func() override {
cout << "for an A, call func1" << std::endl;
}
};
struct B : public Base {
void func() override {
cout << "for a B, call func1 and func2" << std::endl;
}
};
int main() {
A a;
B b;
a.loop();
b.loop();
}
输出:
for an A, call func1
for an A, call func1
for an A, call func1
for an A, call func1
for a B, call func1 and func2
for a B, call func1 and func2
for a B, call func1 and func2
for a B, call func1 and func2
我有两个类似的功能。这两个函数都包含一个嵌套的 for
循环。我如何结合这两个功能来减少重复代码。
funcA
和 funcB
之间的唯一区别是 funcB
在循环中调用 func_2
。
下面两个函数。
void funcA()
{
for (int i = 0; i < size; i++)
{
for (int j = 0; j < size; j++)
{
func_1();
}
}
}
void funcB()
{
for (int i = 0; i < size; i++)
{
for (int j = 0; j < size; j++)
{
func_1();
func_2();
}
}
}
funcA 和 funcB 的唯一区别是 funcB 调用 func_2(); 然后使用标志来控制是否应该调用该方法
void funcC(bool shouldInvokeFunc2)
{
for(int i = 0; i < size; i++)
{
for(int j = 0; j < size; j++) {
func_1();
if(shouldInvokeFunc2) // use the flag
{
func_2();
}
}
}
}
你本可以使用 variadic templates.
template<class ... FuncTypes>
void funcAB(FuncTypes... Funcs)
{
for(int i = 0; i < size; ++i) {
for(int j = 0; j < size; ++j) {
(Funcs(), ...);
}
}
}
调用函数的方法如下。
funcAB(&func_1); // if you want to only call func_1
funcAB(&func_1, &func_2) // if you want both to be called
您可以编写一个接受函数作为参数的函数,但没有更多信息,这是我能给出的唯一示例:
#include <iostream>
constexpr int size = 1;
void func(void (*f)())
{
for(int i = 0; i < size; i++)
{
for(int j = 0; j < size; j++)
{
f();
}
}
}
void func_1(){ std::cout << "func_1" << std::endl; }
void func_2(){ std::cout << "func_2" << std::endl; }
void funcA()
{
func_1();
}
void funcB()
{
func_1();
func_2();
}
int main()
{
func(funcA);
func(funcB);
return 0;
}
也许可以创建一个带参数的函数,具体取决于该参数调用 func_2()
。您还可以为该参数指定一个默认值。
void funcA(bool callFunc2 = false) {
for(int i = 0; i < size; i++) {
for(int j = 0; j < size; j++) {
func_1();
if (callFunc2) {
func_2();
}
}
}
}
funcA()
将 运行 不调用 func_2()
并且 funcA(true)
将 运行 执行 func_2()
.
也许我有点过头了,但是嵌套循环没有明显的原因(func_1()
和 func_2()
都不依赖于 i
或 j
).传递可调用对象的直接方法如下:
template <typename F>
void func(F f) {
for (int i=0; i < size*size; ++i) f();
}
然后调用
func([](){ func_1(); });
func(&func_1); // passing function pointer works as well
或
func([](){ func_1(); func_2(); });
PS:当size*size
可以溢出或为负数时,嵌套循环和平面循环之间存在差异。尽管传递可调用对象与此正交。
您可以用一个 template function. It takes variadic arguments of functions, and each function will be called by the fold expression (Since c++17) 扩展替换它。
此外,使用 ranges::views::iota
(Since c++20) 您可以将两个 for
循环合并为一个。
类似如下:
#include <ranges> // std::views::iota
template<typename... Funcs>
void funcAB(Funcs&&... funcs)
{
for ([[maybe_unused]] int i : std::views::iota(0, size * size)) {
(funcs(), ...);
}
}
您将调用 funcAB
:
funcAB(func1); // for funcA() call
funcAB(func1, func2); // for funcB() call
(Live Demo)
除了其他帖子中提到的将实现作为函数参数传递的不同方式(例如通过 lambda 或函数指针)之外,您还可以考虑继承和覆盖来表达行为的重用:
struct Base {
int size = 2;
void loop() {
for(int i = 0; i < size; i++) {
for(int j = 0; j < size; j++) {
func();
}
}
}
virtual void func() = 0;
};
struct A : public Base {
void func() override {
cout << "for an A, call func1" << std::endl;
}
};
struct B : public Base {
void func() override {
cout << "for a B, call func1 and func2" << std::endl;
}
};
int main() {
A a;
B b;
a.loop();
b.loop();
}
输出:
for an A, call func1
for an A, call func1
for an A, call func1
for an A, call func1
for a B, call func1 and func2
for a B, call func1 and func2
for a B, call func1 and func2
for a B, call func1 and func2