7

How can I refactor the following C++ code? I am using C++11 in my program

void f(int a, int b, int c, int d, int e, int f) {

  // MAX1..MAX6 are constants, N1..N6 are constants
    if( a > MAX1) {
        .. code block 1..
    }
    else if(b > MAX2) {
        .. code block 2..
    }
    else if(c > MAX3) {
        .. code block ..
    }
    else if(d > MAX4) {
        .. code block 3 ..
    }
    else if(e > MAX5) {
        .. code block 4 ..
    }
    else if(f > MAX6) {
        .. code block5 ..
    }
    else if(( a > N1) && ( b > N2)) {
            .. code block 6 ..
    }
    else if(( c > N3) && ( d > N4)) {
            .. code block 7 ..
    }
    else if (( e > N5) && ( f > N6)) {
            .. code block 8 ..
    }
    else if (( a > N1) && ( b > N2) && (d > N4)) {
            .. code block 9 ..
    }
    else if (..some combination of (a > N1) to (f > N6)...) {
            // there are more than 30 such combinations in my code
            .. code block XX ..
    }
    else {
            .... code block ....
    }
4

6 回答 6

1

函数中最多有 64 个代码块,每个代码块可以使用匿名函数,也可以使用命名函数:

my_func_array[64] = {
    [CONDITION(1,0,0,0,0,0)] = { codeblock1 },
    [CONDITION(0,1,0,0,0,0)] = { codeblock2 },
     ...
};

该宏基本上会将 6 个第一个输入连接到一个索引,基本上转换为:

 my_func_array[64] = {
    [32] = { ... },
    [16] = { ... },
 };

这意味着您不必以任何特定顺序输入条件...

运行时,您还必须评估所有条件:

 int condition = CONDITION(a < MAX1, b < MAX2, c < MAX2, ...);
 if (my_func_array[condition])
      my_func_array[condition]();
 else
 {
      // this second block should cover all the other cases
      int condition2 = CONDITION(a < N1, b < N2, c < N3, ... );
      if (my_func_array2[condition2])
          my_func_array2[condition2]();
 }
于 2013-09-18T17:36:41.507 回答
0

因此,假设您有一个互斥整数范​​围(xi 到 yi)的离散数 N,并且您想根据给定输入 z 的范围调用某个代码块,那么:

  • 您想使用std::map二叉树来存储每个范围的开始和相应的 lambda。
  • 调用std::lower_boundon z 来查找候选范围
  • 然后根据 z 检查该范围的上限。
  • 如果在里面,调用 lambda

与大 if-else 链的 O(n) 相比,这将给出 O(log(N)) 时间。

于 2013-09-18T17:20:15.893 回答
0

您当然可以从创建athrough fMAXNinto 数组开始(只是一个起始草图,我可以用更多关于您的条件、代码块和用途的信息进行扩展):

const int MAX[6] = { ... };
const int N[6] = { ... };
const std::function funcs[6];

void f(int in[6])
{
    for(int i = 0; i < 6; ++i)
    {
        if(in[i] > MAX[i])
        {
            funcs[i]();
            break;
        }
    }
}
于 2013-09-18T16:57:39.040 回答
0

首先,我会按照Mark B的建议摆脱前 6 个分支,但是

  • 而不是break我会return

  • 我会简单地使用函数指针,std::function在这里有点矫枉过正,

  • 我会使用std::array和绑定检查而不是原始数组。

现在无聊的案例已经过去了,我将对剩余的分支应用相同的模式,但它需要一些技巧,因为这些条件是复合的。

我假设MAX1 > N1. 我希望这是真的。

首先,我将构建一个十进制数,对所有参数进行编码:

int arg=10^5*(a>N1?1:0)+10^4*(b>N2?1:0)+10^3*(c>N3?1:0)+10^2*(d>N4?1:0)+10*(e>N5?1:0)+(f>N1?1:0)

我也会以类似的方式对条件进行编码。例如:条件(a > N1) && ( b > N2)变为arg >= 110000等。

如您所见,在此编码之后,您可以以与前 6 个分支相同的方式消除剩余的分支。

如果效率是一个主要问题,您可以使用 2 的幂(移位然后使用位掩码)执行相同的技巧。我不会摆弄,所以我无法帮助你,但它的工作方式相同,而且效率更高。可能与现在拥有的那样长的 if-else if 链一样有效,或者甚至更有效,因为您不重复相同的比较。

希望这可以帮助。

于 2013-09-18T18:12:50.393 回答
0

你所拥有的似乎并不合理,但如果你真的想重构,你可以创建一个枚举

枚举类 CaseSelect {CASE0, CASE1, CASE2};

然后创建一个看起来与您当前的 if 树非常相似的函数,每个代码块都返回适当的枚举。

然后使用枚举创建一个 case 语句,每个中都有适当的逻辑

它不会给你带来太多好处,但它将选择状态的逻辑与操作逻辑分开,这在多行语句的情况下可能有助于清晰

于 2013-09-18T16:53:58.143 回答
-1

如果有很多规则,函数对象(例如:lambdas)可能会在那里进行救援:

出于演示目的,我对其进行了一些简化,只有 3 个参数...

而且我认为在这种情况下,非检查有一个安全的价值0(没有它可以生存,但看起来会更丑)。

#include <iostream>
#include <functional>

struct Rule {
    int a;
    int b;
    int c;
    std::function<int()> fun;
};

Rule rules[]{
    { 10, 0, 0, []() { std::cout << "First!"; return 0;} },
    { 0, 20, 0, []() { std::cout << "Second!"; return 1;} }
};

int f(int a, int b, int c) {
    for (Rule rule : rules) {
        if ((rule.a == 0 || a > rule.a)
         && (rule.b == 0 || b > rule.b)
         && (rule.c == 0 || c > rule.c))
            return rule.fun();
    }
    std::cout << "Not match!";
    return 2;
}

int main() {
    f(5, 23, 3);
};
于 2013-09-18T16:56:43.497 回答