我有两个类似的函数。这两个函数都包含一个嵌套的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();
}
}
}
你可以使用可变的模板。
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()
都不依赖于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
可以溢出或为负时,嵌套循环和平面循环之间存在差异。尽管传递可调用对象与此是正交的。
你可以用一个模板函数代替它。它接受函数的可变参数,并且每个函数都将通过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