0

私はどこでも探しています (モダン C++ デザイン & co) が、さまざまな引数を受け入れ、さまざまなクラスで動作する一連のコールバックを格納するための良い方法を見つけることができません。これが必要なのは、アプリケーションのすべてのオブジェクトが、そのメソッドの 1 つの実行をClock、現在の時間を追跡し、適切なタイミングでこのメソッドを呼び出すことができるマスター オブジェクトに延期できるようにするためです。私が目指しているコードは、次のようなものです。

void executeAction1Deferred(int time, int arg1, bool arg2)メソッドではclass1、 time は将来必要な実行時間であり、次のようなものがあるはずです。

Clock::defer(time, Class1::action1, this, arg1, arg2);

このClock::defer(??? what signature ????)タスクを表すオブジェクトでは、時間がキーである優先キューに格納されます。すべてClockのクォンタムについて、タスクのリストがトラバースされ、このクォンタムで実行する必要があるタスクが実行されます。シングルトンのオブジェクトを意図しているため、「延期」を静的関数として使用したことに注意してください。ただしClock、メンバー関数にすることもできます。選択の問題です。

void*可変数の引数を保持するために を使用することを考えましたが、この関数を遅延せずに直接使用するたびに引数の構造体を作成する必要があるため、action1()メソッドが a を受け入れるのはかなりひどいです。void*

私は過去に何度もこの問題に直面してきましたが、本当に適切な解決策を見つけたことはありません。これは小規模なマルチプラットフォーム プロジェクトであり、経験の浅いプログラマーが拡張できるビルドのシンプルさが不可欠​​であることに注意してください。ブーストは使用したくありません。ただし、対処するプラットフォームのすべてのコンパイラにはstd::tr1バインドがあります。問題は、ジェネリック関数のコンテナーを定義する方法です。これらのそれぞれは可変数のパラメーター (最大 N ~ 5) を受け入れ、共通の仮想クラスから派生しないオブジェクトの異なるメンバー メソッドになります。ありがとう

4

3 に答える 3

7

を使用std::function<void()>して呼び出しを保存し、可変引数テンプレート引数を使用して関数パラメーターを転送およびバインドします。

class Clock
{
    vector<function<void()>> tasks;

    template<class F, class... Args>
    void defer(F f, Args&&... args)
    {
        tasks.push_back(bind(f, forward<Args>(args)...);
    }

}

void f(A a, B b);

int main()
{
    A a;
    B b;

    Clock c;
    c.push_back(f, a, b);
}

も参照std::bindしてください。std::mem_fun

于 2012-12-04T13:32:16.593 に答える
2

C ++ 11では、を保存しstd::function<void()>ます。std::bind次のように、別のシグニチャの1つから関数を作成するために使用できます。

std::vector<std::function<void()>> deferred;
deferred.push_back(std::bind(&Class1::action1, this, arg1, arg2));

// later...
for (auto f : deferred) f();

C ++ 11がオプションでない場合、Boostには非常によく似たテンプレートがfunctionあります。bind確認すべき歴史的な参照はありませんが、TR1にも存在する可能性があると思います。

Boostが本当にオプションではない場合(そしてTR1がこれらを提供していない場合)、それをオプションにすることを強くお勧めします。それ以外の場合は、これを実装する方法の例としてBoostを使用します。可変個引数テンプレートがないと、非常に毛むくじゃらになります。

(そして、Modern C ++ Designについて言及しているので、型リストのセクションを読んでください。これは、可変個引数テンプレートなしで行う方法です)。

于 2012-12-04T13:38:04.660 に答える
1

コールバックは提供された引数を含めて延期されるため、実際のシグネチャは次のようvoid()になります。つまり、Clockオブジェクトはそれ自体で引数を提供せず、結果を評価する必要はありません。したがって、一般的には、メンバー関数ポインター(または他の関数ポインター)を必要な引数と一緒にバインドし、結果(関数オブジェクト)をクロックに渡す必要があります。これがboost::bind/std::tr1::bindboost::function/std::function<void()>の出番です-またはC++11ラムダ:

Clock::defer(time, boost::bind(&Class1::action1, this, arg1, arg2));
//C++11 lambda:
Clock::defer(time, [=](){action1(arg1, arg2);} );

しかし、あなたがしていることはすでに行われています-Boost.Asioタイマーを見てください:

boost::asio::basic_deadline_timer timer(ioService, expiryTime);
timer.async_wait([=](){action1(arg1, arg2);} //perform action1 when the timer is done
于 2012-12-04T13:38:24.380 に答える