如何重构嵌套for循环?



我有两个类似的函数。这两个函数都包含一个嵌套的for-循环。如何结合这两个函数来减少重复的代码。

funcAfuncB的唯一区别是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();
}
}
}

你可以使用可变的模板。

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

也许我有点过头了,但是嵌套循环没有明显的原因(func_1()func_2()都不依赖于ij)。传递可调用对象的直接方法如下:

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可以溢出或为负时,嵌套循环和平面循环之间存在差异。尽管传递可调用对象与此是正交的。

你可以用一个模板函数代替它。它接受函数的可变参数,并且每个函数都将通过fold表达式(自c++17起)展开来调用。此外,使用ranges::views::iota(自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

(现场演示)

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();
}     
}
}
}

你可以写一个函数接受一个函数作为参数,但没有更多的信息,这是我能给的唯一的例子:

#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()的情况下运行。

除了在其他帖子中提到的作为函数参数传递实现的不同方式(例如通过lambdas或函数指针)之外,您可以考虑通过继承和重写来表达行为的重用:

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

相关内容

  • 没有找到相关文章

最新更新