1

私は線形遺伝的プログラミング プロジェクトを行っています。このプロジェクトでは、自然な進化メカニズムによってプログラムが繁殖および進化します。彼らの「DNA」は基本的に、利用可能な関数のセットへの関数ポインタを含むコンテナです(私は配列とベクトルをうまく使用しました)。ここで、数学の問題などの単純な問題の場合、1 つの型定義関数ポインターを使用して、すべてが double を返し、すべてが 2 つの double をパラメーターとして受け取る関数を指すことができます。

残念ながら、これはあまり実用的ではありません。さまざまな種類の関数ポインターを持つことができるコンテナーを持つことができる必要があります。たとえば、引数を取らない関数への関数ポインター、引数を 1 つ取る関数、何かを返す関数などです (考え)...

任意の種類のコンテナを使用してこれを行う方法はありますか? さまざまな種類の関数ポインターを持つポリモーフィック クラスを含むコンテナーを使用してそれを行うことはできますか? これまでに行ったすべてを再設計するのは苦痛になるため、誰かが私を解決策に向けてくれることを願っています.

4

4 に答える 4

2

仮想マシンの一般的なアイデアは、引数と戻り値の受け渡しに使用される別のスタックを持つことです。

関数は引き続きすべて void fn(void) 型にすることができますが、引数の受け渡しと戻りは手動で行います。

次のようなことができます。

class ArgumentStack {
    public:
        void push(double ret_val) { m_stack.push_back(ret_val); }

        double pop() {
             double arg = m_stack.back();
             m_stack.pop_back();
             return arg;
        }

    private:
        std::vector<double> m_stack;
};
ArgumentStack stack;

...したがって、関数は次のようになります。

// Multiplies two doubles on top of the stack.
void multiply() {
    // Read arguments.
    double a1 = stack.pop();
    double a2 = stack.pop();

    // Multiply!
    double result = a1 * a2;

    // Return the result by putting it on the stack.
    stack.push(result);
}

これは次のように使用できます。

// Calculate 4 * 2.
stack.push(4);
stack.push(2);
multiply();
printf("2 * 4 = %f\n", stack.pop());

フォローしますか?

于 2011-01-15T10:30:27.903 に答える
1

あなたが言及したこと自体は、おそらくのようなコンテナ std::functionまたは識別されたユニオンによって実装できますBoost::variant
例えば:

#include <functional>
#include <cstdio>
#include <iostream>

struct F {
  virtual ~F() {}
};

template< class Return, class Param = void >
struct Func : F {
  std::function< Return( Param ) >  f;
  Func( std::function< Return( Param ) > const& f ) : f( f ) {}
  Return operator()( Param const& x ) const { return f( x ); }
};

template< class Return >
struct Func< Return, void > : F {
  std::function< Return() >  f;
  Func( std::function< Return() > const& f ) : f( f ) {}
  Return operator()() const { return f(); }
};

static void f_void_void( void ) { puts("void"); }
static int f_int_int( int x ) { return x; }

int main()
{
  F  *f[] = {
    new Func< void >( f_void_void ),
    new Func< int, int >( f_int_int ),
  };

  for ( F **a = f, **e = f + 2;  a != e;  ++ a ) {
    if      ( auto p = dynamic_cast< Func< void >*     >( *a ) ) {
      (*p)();
    }
    else if ( auto p = dynamic_cast< Func< int, int >* >( *a ) ) {
      std::cout<< (*p)( 1 ) <<'\n';
    }
  }
}

しかし、これが本当にあなたが望むものかどうかは
わかりません. Alf P. Steinbach のコメントについてどう思いますか?

于 2011-01-15T12:49:41.810 に答える
1

異なるものを受け取る (または返す) 関数は、ポリモーフィズムで必要とされる同じ方法 (同じインターフェイスを使用)で使用できないため、クラスにポリモーフィック関数を配置することはできません。

必要な関数タイプの仮想関数を提供するクラスを持つという考えは機能しますが、(問題について何も知らなくても!) その使用法は私には奇妙に感じます: 派生クラスはどの関数をオーバーライドしますか? あなたの機能は無相関ではありませんか?

関数が相関していない場合 (同じクラスのメンバーとしてグループ化する理由がない場合、またはメンバー変数を必要としないために静的関数になる場合)、別のものを選択する必要があります...関数をランダムに作成する場合は、関数タイプ用に 1 つ、複数の異なるコンテナーを用意し、コンテナーをランダムに選択してから、その中の関数を選択するだけです。

あなたの関数が何をするかの例をいくつか挙げていただけますか?

于 2011-01-15T10:14:42.350 に答える