0

也许我已经被 Ruby 宠坏了,但在我看来,如果我有两个使用相同基本逻辑(但细节不同)的函数,我应该只需要编写一次逻辑——因此,我应该只需要在一个地方维护代码。

这是基本逻辑,我在许多不同的功能中重复使用。更改的部分标记为 A、B、C、D、E 和 F。

  if (recursions) {
    while (lcurr || rcurr) {

      if (!rcurr || (lcurr && (lcurr->key < rcurr->key))) {
        // A
        lcurr   = lcurr->next;
      } else if (!lcurr || (rcurr && (rcurr->key < lcurr->key))) {
        // B
        rcurr   = rcurr->next;
      } else { // keys are == and both present
        // C
        lcurr   = lcurr->next;
        rcurr   = rcurr->next;
      }
    }
  } else {
    while (lcurr || rcurr) {
      if (!rcurr || (lcurr && (lcurr->key < rcurr->key))) {
        // D
        lcurr         = lcurr->next;
      } else if (!lcurr || (rcurr && (rcurr->key < lcurr->key))) {
        // E
        rcurr         = rcurr->next;
      } else { // keys == and both left and right nodes present
        // F
        lcurr         = lcurr->next;
        rcurr         = rcurr->next;
      }
    }
  }

函数的返回值也可能不同。如果可能的话,我希望能够在不同的地方有额外的逻辑。

我意识到这可以通过 C 宏来完成,但它们似乎不是特别易于维护。我也意识到,如果我的矩阵类型使用嵌套的 STL 列表,这可能会更容易。但是C++11(或旧的C++)中是否有任何功能允许这个逻辑只写一次?也许有人可以用 lambdas 做到这一点吗?

4

3 回答 3

1
template<typename A, typename B, typename C>
void compute (/*some parameters */)
{
   if (recursions) {
     while (lcurr || rcurr) {
       if (!rcurr || (lcurr && (lcurr->key < rcurr->key))) {
         auto aResult = A (lcurr, rcurr);
        lcurr   = lcurr->next;
       } else if (!lcurr || (rcurr && (rcurr->key < lcurr->key))) {
        auto bResult = B (lcurr, rcurr);
       } // ... and so on
       C (aResult, bResult);
    } // ... etc
} 

要打电话compute,您需要编写要传递的来代替 A 到 F 占位符。实际工作是在每个类的operator()成员函数中完成的。

class A1 {
  public:
    double operator() (SomeType t1, SomeType t2) {
      // do work
    }
};

class A2 {
  public:
    int operator() (SomeType t1, SomeType t2) {
      // do work
    }
};

class B1 {
  public:
    char* operator() (SomeType t1, SomeType t2) {
      // do work
    }
};

class B2 {
  public:
    SomeClass* operator() (SomeType t1, SomeType t2) {
      // do work
    }
};

class C1 {
  public:
    int operator() (double t1, char* t2) {
}

class C2 {
  public:
    int operator() (int t1, SomeClass* t2) {
}

compute<A1, B1, C1>(whatever);
compute<A2, B2, C2>(whatever);

请注意 A1 和 B1 返回类型如何匹配 C1 参数,对于 A2、B2 和 C2 也是如此。

auto需要C++11,如果你不能使用它,你将不得不做一些额外的工作:

class A1 {
  public:
    typedef double result_type;
    double operator() (SomeType t1, SomeType t2) {
      // do work
    }
};

和里面compute

             typename A::result_type aResult = A (lcurr, rcurr);
于 2013-08-02T09:51:49.847 回答
1

好吧,一种解决方案是抽出一些冗余代码并将其放入模板中,例如

  template<T1, T2, T3>
  bool TESTKEYS(T1 lcurr, T2 rcurr, T3 actor)
  {
    while (lcurr || rcurr) {
      if (!rcurr || (lcurr && (lcurr->key < rcurr->key))) {
        if (actor.TestLeft(....)) return false;
        lcurr         = lcurr->next;
      } else if (!lcurr || (rcurr && (rcurr->key < lcurr->key))) {
        if (actor.TestRight(....)) return false;
        rcurr         = rcurr->next;
      } else { // keys == and both left and right nodes present
        if (actor.TestBoth(....)) return false;
        lcurr         = lcurr->next;
        rcurr         = rcurr->next;
      }
    }
    return true;
  }

您需要自己决定 TestLeft 使用哪些参数等。

于 2013-08-01T18:47:24.643 回答
1

我看到的方法是编写回调函数。因此,您将编写一次逻辑部分,就像您在第二个文本块中一样。您还可以定义函数 A、B、C、D、E 和 F。

在您的逻辑函数中,您将传入所需的参数和指向回调函数的指针。然后,在逻辑函数中,您将调用这些回调并向它们传递所需的参数。

老实说,这似乎最终会做得更多。你会为你的逻辑维护一个单一的事实点,但函数指针可能是一个巨大的痛苦,并降低你的代码的可读性。

为了提供尽可能多的信息,举个例子:

int addTwoNumbers(int a, int b) { //A simple adding function
   return a + b; 
}

int subtractTwoNumbers(int a, int b) { //A simple subtracting function
    return a - b;
}

/*
 * This is the fun one. The first argument is a pointer to a function. The other 
 * arguments are the numbers to do math with. They aren't as important.
 * The important part is that, so long as the function declaration matches the one here
 * (so a function that returns an int and takes in two ints as arguments) it can be
 * used by this function
 */
void math(int (*mathFunc)(int, int), int one, int two) {
    cout << *mathFunc(one, two);
}

int main(int argc, char* argv[]) {
    int whichMath = 0; //Assume 1 is add, 2 is subtract
    if(whichMath == 1) {
        math(&addTwoNumbers, 5, 6); //we're going to add 5 and 6
    } else {
        math(&subtractTwoNumbers, 5, 6); // we're going to subtract 5 and 6
    }
}

如果这没有意义,那么欢迎您加入我们这些与函数指针斗争的军团。同样,我想说你应该只编写两个单独的函数,因为你可以看到这会变得多么丑陋。

作为免责声明,我没有编译此代码。我在工作,这些机器上没有 c++ 编译器。

我过去曾大量使用此站点作为函数指针的参考:http: //www.newty.de/fpt/fpt.html#defi

于 2013-08-01T18:43:09.470 回答