1

我有一个编程问题,我想了好几天,但仍然没有好的解决方案。

有几个大的,长的,类似的功能,其中只有几行不同。例如:

    void bigfunc(){
       //blabla..
       double i, j, k;
       double result;

      //only this part is different
      { result=i++; }              //in bigfunc1;
      { result=i*cos(j);}          //in bigfunc2;
      { result=sin(i)*cos(j)*tan(k);}     //in bigfunc3;

      //blabla...
    }

最简单的方法是复制 bigfunc 3 次并分别编辑不同的行。显然,这不是一个好主意。

现在,我选择了c++中的模板函数方法,它将不同的行包含在几个小函数中,例如:

    < template class F >
     void bigfunc(F& f){

      ...
      f(i,j,k); //call the function.
      ...
    }

      void f1(int i, int j, int k){
          i++; //only use parameter i!
      }  
      void f2(int i, int j, int k){
          i++; j++; //only use parameter i and j!
      }  
      void f3(int i, int j, int k){
          i++; j++; j++;
      }  

但是,我们必须统一 f(int, int, int) 的原型,以将所有输入参数包含在三个不同的 bigfunc 中,而实际上,例如在 bigfunc1 中,确实只需要 f(int i)。因此,这种方法似乎不够优雅。

我认为,如果有一些抽象机制可以将句子块作为函数参数或模板函数参数。那将是惊人的!例如(伪代码):

       < template class Code>
       void bigfunc(Code code){
        //...

         code(); //direct expand the code in place, which will be amazingly beautiful.
        //....
       }

       code1(){
            i++;   //just be care for the variable name, like #include
       }
       ....

任何语言中是否还有其他一些编译器时抽象机制可以优雅地解决此类问题。

到目前为止,我只听说D语言的static_if也许可以解决这种情况。例如:

      < template class F>
      void bigfunc(F f){

           if( static_if(f) == func1 ) //it is justified at compile-time, not at run-time.
              i++;
           else if ( static_if(f)==func2){
               i++; j++;
           }...
      }

对不起,我不知道 D,这只是为了解释。

感谢您的任何建议!

4

7 回答 7

5

你可以在 D 中用几种不同的方式来做。一种是:

void bigfunc(string code)(){
   //blabla..
   double i, j, k;
   double result;

  //only this part is different
  mixin(code);

  //blabla...
}

alias bigfunc!"{ result=i++; }" bigfunc1;
alias bigfunc!"{ result=i*cos(j); }" bigfunc2;
alias bigfunc!"{ result=sin(i)*cos(j)*tan(k);}" bigfunc3;

这类似于 C 宏方式 - 您将字符串传递给模板(第一组参数是编译时模板参数,第二组是常规函数参数),然后将其作为代码混合以创建函数。

如果足够容易,您也可以使用静态来完成。

void bigfunc(int version)(){
   //blabla..
   double i, j, k;
   double result;

    static if(version == 1)
          { result=i++; }
    else static if(version == 2)
// well you get the idea

然后,您可以将不同的模板参数别名为新名称,就像使用字符串一样。

于 2013-06-11T01:16:56.857 回答
2

你可以只使用一个宏:

#define CREATE_FUNC(name, code)    \
void name(){                       \
   //blabla..                      \
   int i, j, k;                    \
                                   \
  //only this part is different    \
  code                             \
                                   \
  //blabla...                      \
}

CREATE_FUNC(bigfunc1, { i++; });
CREATE_FUNC(bigfunc2, { i++; j++; });
CREATE_FUNC(bigfunc3, { i++; j++; k++; });

然而,不是那么漂亮和“c-plus-plussy”。

于 2013-06-09T19:58:38.660 回答
2

您正在寻找的神秘编程语言功能称为“子程序”:

void bigfunc(int variant){
   //blabla..
   double i, j, k;
   double result;

  //only this part is different
  switch (variant) {
  case 0: { result=i++; } break;             //in bigfunc1;
  case 1: { result=i*cos(j);} break;          //in bigfunc2;
  case 2: { result=sin(i)*cos(j)*tan(k);} break;     //in bigfunc3;
  }

  //blabla...
}

void bigfuncA() { bigfunc(0); }
void bigfuncB() { bigfunc(1); } 
void bigfuncC() { bigfunc(2); }
于 2013-06-10T03:24:38.177 回答
1

不太确定这是您所追求的,但函数对象可能会起作用。

template<typename Func, typename... Args>
void bigfunc(Func f, Args... args) {
  //blahblah
  f(args...);
  //blahblah
}

struct f1 {
    void operator()(int& i) {
        ++i;
    }
};

struct f2 {
    void operator()(int& i, int& j) {
        f1()(i);
        ++j;
    }
};

struct f3 {
    void operator()(int& i, int& j, int& k) {
        f2()(i, j);
        ++k;
    }
};

//main...
int i, j, k;
//...
bigfunc(f3(), i, j, k);
于 2013-06-09T04:38:29.867 回答
0

为什么不将“通用代码”放在一个内联函数中,然后所有三个函数都将调用该函数?

于 2013-06-09T03:38:07.653 回答
0

这很容易通过编写一个高阶函数 (HOF) 来解决,这是函数式编程的一种范式。一个常见的用例是打开一个文件,对它做一些事情,然后再次关闭它。传统且容易出错的方法是手动执行此操作。HOF 提供了一个优雅的替代方案:

void *withFile(const char *fp, const char *mode, void *(*k)(FILE *)) {
    FILE *fh;
    void *result;

    fh = fopen(fp, mode);
    if (fh == NULL) return NULL;
    result = k(fh);
    fclose(fh);
    return result;
}

现在您可以编写几个只处理实际文件读取的小函数。withFile 过程确保文件始终关闭。对于这个范式更深入的解释,你可以阅读我的旧博客文章

请注意,用户函数并不关心它是否传递了额外的参数。只需忽略用户函数中的额外参数。

于 2013-06-09T04:17:52.513 回答
0

您的第一个模板方法看起来并不太可怕,除非分析证明否则编译器可能会优化掉不需要的函数和未使用的变量,特别是如果您没有在 f1 和 f2 的声明中给它们命名。

但是为了概括事物,您需要退后一步,以抽象的方式思考您实际想要做的事情,而不是考虑在具体案例中您是如何做到的。i,j,k 实际上是什么意思?您有一组计数器变量,并且在您的 bigfunction 中的某个时刻,您想要增加所有这些变量:

template <int N>
struct Counting_Variables;

template <>
struct Counting_Variables<1> {
    int i;
};

template <>
struct Counting_Variables<2> {
    int i, j;
};

template <>
struct Counting_Variables<3> {
    int i,j,k;
};

void increase_counters ( Counting_Variables<1> & arguments ) {
    ++(arguments.i);
}

void increase_counters ( Counting_Variables<2> & arguments ) {
    ++(arguments.i);
    ++(arguments.j);
}

void increase_counters ( Counting_Variables<3> & arguments ) {
    ++(arguments.i);
    ++(arguments.j);
    ++(arguments.k);
}

void bigfunction () {
    // Enter appropriate number of counter variables as template argument here:
    Counting_Variables<2> counters;

    // Be lazy and introduce shortcuts for counters.i etc.
    int & i = counters.i;
    int & j = counters.j;


    // do some stuff here

    // increase all the counters
    increase_counters( counters );

    // do more stuff here
};

我被指控有罪,将 Counting_Variables 设为模板并不是绝对必要的。将它们称为 Counting_Variables_with_i_and_j 而不是 N=2 具有相同的效果。

于 2013-06-09T08:59:20.987 回答