7

この C++ クラスにcomputeは、同じクラスのメソッドである「計算カーネル」でフィードしたい 1 つの大きな複雑なメソッドがあります。私はの線に沿って何かをするだろうと思います

class test {
int classVar_ = 42;

int compute_add(int a, int b)
{
   compute(int a, int b, this->add_())
}

int compute_mult(int a, int b)
{
   compute(int a, int b, this->mult_())
}


int compute_(int a, int b, "pass in add or multiply as f()")
{
   int c=0;
   // Some complex loops {
   c += f(a,b)
   // }
   return c;
}

int add_(int a, int b){a+b+classVar_;}
int multiply_(int a, int b){a*b+classVar_;}
...

}

addしかし、 orをどのように渡すのかわかりませんmultiply。このアプローチに代わる方法は、 or を指定する何らかの種類の an を渡すことですが、ENUMループ内でa orを避けたかったのです。add()multiply()switchif

ここでのベストプラクティスは何ですか?

4

3 に答える 3

5

ご想像のとおり、メンバー関数ポインターを渡すことは許容される方法です。

構文を知る必要がある場合は、次のとおりです。

int compute_(int a, int b, int (test::*f)(int,int))
{
   int c=0;
   // Some complex loops {
   c += (this->*f)(a,b)
   // }
   return c;
}

整数を使用してメンバー関数を表し、切り替えを行うと、使用可能な操作のリストが変更されたときに最新の状態に保つためのプログラマーのオーバーヘッドが発生します。したがって、特定のケースで重要な理由がない限り、それは望ましくありません。

1 つの代替方法は、computeさらに一般化することです。メンバー関数を使用する代わりに、任意の呼び出し可能な型を使用する関数テンプレートを記述します。

template <typename BinaryFunction>
int compute_(int a, int b, BinaryFunction f) {
    // body as before but `f(a,b)` instead of `(this->*f)(a,b)`
}

このより一般的なテンプレートは、 のメンバー関数ではない独自の発明の演算子で使用したい場合に最適ですtest。ただし、誰かが をキャプチャする必要があるため、メンバー関数の場合は使用が難しくなりますthis。これを行うにはいくつかの方法があります - C++11 ラムダ、boost::bind、またはファンクターの手書き文字を書き出すことです。例えば:

template <typename BinaryFunction>
int compute_(int a, int b, BinaryFunction f) {
    // body as before with `f(a,b)`
}

int compute_(int a, int b, int (test::*f)(int,int))
{
    return compute_(a, b, bind_this(f, this));
}

定義bind_thisは少し面倒です:バイナリ ファンクターしかとらないのに、std::bind1st引数が 3 のファンクターを使用したいという点を除いては似ています。、およびC++11 では、より柔軟で、余分な引数を処理します。この場合は次のようにしますが、一般に 2 引数のメンバー関数をバインドするには機能しません。bind1stboost::bindstd::bind

struct bind_this {
    int (test::*f)(int,int);
    test *t;
    int operator(int a, int b) const {
        return (t->*f)(a,b);
    }
    bind_this(int (test::*f)(int,int), test *t) : f(f), t(t) {}
};

C++11 では、ラムダを使用できます。

int compute_(int a, int b, int (test::*f)(int,int))
{
    return compute_(a, b, [=](int c, int d){ return (this->*f)(c,d) });
}
于 2012-06-29T10:45:45.100 に答える
1

2 つの選択肢があります。

  1. メンバー関数へのポインターの使用
  2. ラムダ関数の使用

メンバー関数へのポインターを使用した例:

#include <iostream>

class D
{
public:
  D(int v ) : classVar_(v){}
  int add_(int a, int b){return (a+b+classVar_);}
  int multiply_(int a, int b){return (a*b+classVar_);}
private:
  int classVar_;
};

class test {
public:

int compute_(int a, int b, D &d, int (D::*f)(int a, int b))
{
   int c=0;
   // Some complex loops {
   c += (d.*f)(a,b);
   // }
   return c;
}

};

int main()
{
  test test;
  D d(1);

  std::cout<<"add : " << test.compute_( 5, 4, d, &D::add_ ) << std::endl;
  std::cout<<"add : " << test.compute_( 5, 4, d, &D::multiply_ ) << std::endl;
}

lambda を使用した例:

#include <iostream>
#include <functional>

class D
{
public:
  D(int v ) : classVar_(v){}
  int add_(int a, int b){return (a+b+classVar_);}
  int multiply_(int a, int b){return (a*b+classVar_);}
private:
  int classVar_;
};

class test {
public:

int compute_(int a, int b, std::function< int(int,int) > f)
{
   int c=0;
   // Some complex loops {
   c += f(a,b);
   // }
   return c;
}

};

int main()
{
  test test;
  D d(1);

  std::cout<<"add : " << test.compute_( 5, 4, [&d](int a, int b){ return d.add_(a,b); } ) << std::endl;
  std::cout<<"add : " << test.compute_( 5, 4, [&d](int a, int b){ return d.multiply_(a,b); } ) << std::endl;
}
于 2012-06-29T10:42:53.883 に答える
1

関数へのポインターを使用します。

int compute(int a, int b, int (test::*f) (int, int) )
{
   int c=0;
   // Some complex loops {
   c += (this->*f)(a,b)
   // }
   return c;
}
于 2012-06-29T10:47:07.373 に答える