6

ライブラリの場合、関数が別の関数とその引数を受け入れ、後で呼び出すためにそれらをすべて保存するようにします。引数は型の任意の混合を許可する必要がありますが、関数はvoidを返すだけで済みます。このようなもの:

void myFunc1(int arg1, float arg2);
void myFunc2(const char *arg1);
class DelayedCaller
{ ...
public:
    static DelayedCaller *setup(Function func, …);
};

...
DelayedCaller* caller1 = DelayedCaller::setup(&myFunc1, 123, 45.6);
DelayedCaller* caller2 = DelayedCaller::setup(&myFunc2, "A string");

caller1->call(); // Calls myFunc1(), with arguments 123 and 45.6
caller2->call(); // Calls myFunc2(), with argument "A string"

1つのアプローチは、DelayedCaller :: setup()にstd :: functionを受け入れさせ、私のライブラリユーザーにsetup()を呼び出す前にstd :: bind()を使用させることです。ただし、ユーザーが自分でバインディングを行う必要がないようにsetup()を実装する方法はありますか?

編集:DelayedCallerは既存のクラスです。setup()は、追加したい新しい静的メソッドです。

4

4 に答える 4

8

可変個引数テンプレートを使用して、関数std::bind()内から呼び出すことが可能です。setup()

#include <iostream>
#include <string>
#include <functional>
#include <memory>

void myFunc1(int arg1, float arg2)
{
    std::cout << arg1 << ", " << arg2 << '\n';
}
void myFunc2(const char *arg1)
{
    std::cout << arg1 << '\n';
}

class DelayedCaller
{
public:
    template <typename TFunction, typename... TArgs>
    static std::unique_ptr<DelayedCaller> setup(TFunction&& a_func,
                                                TArgs&&... a_args)
    {
        return std::unique_ptr<DelayedCaller>(new DelayedCaller(
            std::bind(std::forward<TFunction>(a_func),
                      std::forward<TArgs>(a_args)...)));
    }
    void call() const { func_(); }

private:
    using func_type = std::function<void()>;
    DelayedCaller(func_type&& a_ft) : func_(std::forward<func_type>(a_ft)) {}
    func_type func_;
};

int main()
{
    auto caller1(DelayedCaller::setup(&myFunc1, 123, 45.6));
    auto caller2(DelayedCaller::setup(&myFunc2, "A string"));

    caller1->call();
    caller2->call();

    return 0;
}

出力:

123、45.6
文字列

std::unique_ptr生のポインターを返す代わりに、 などのスマート ポインターを返します (または、値によって戻り、動的割り当てを回避func_typeします。コンストラクターとムーブ代入演算子は、特定の条件下で生成されます)。

于 2013-02-12T13:35:36.790 に答える
7

ラムダ関数を使用してバインディングを非表示にすることができます。

#include <functional>

class DelayedCaller : public std::function< void(void) > {
public:
    DelayedCaller(std::function< void(void) > fn)
      : std::function< void(void) >(fn) {}
};

DelayedCaller caller1([]() { myFunc1(123, 45.6); });
DelayedCaller caller2([]() { myFunc2("A string"); });

caller1(); // Calls myFunc1(), with arguments 123 and 45.6
caller2(); // Calls myFunc2(), with argument "A string"

これにより、ライブラリのユーザーの柔軟性も高まります。これらは単一の関数呼び出しに限定されず、関数は作成された元の環境にアクセスできます。

int x;

DelayedCaller caller3 = [&x]() {
    if (x == 0)
        DoSomething();
    else
        DoSomethingElse();
};
于 2013-02-12T13:08:41.253 に答える
0

C++ 11の将来のライブラリを利用したい/利用できる場合は、使用できますstd::async

#include <future>

auto caller = std::async(myFunc1, 123, 45.6); // Creates a future object.

caller.get(); // Waits for the function to get executed and returns result.

遅延評価を強制するには:

auto caller = std::async(std::launch::deferred, myFunc1, 123, 45.6);

また、これには、関数呼び出しがマルチコア ハードウェアを利用する別のスレッドで実行される可能性があるという利点があります。ただし、これはすべての場合に適しているとは限りません。

于 2013-02-12T13:07:50.553 に答える
0

インターフェイスを維持しながら、呼び出しサイトから引数バインディングを非表示にすることが唯一の関心事である場合は、可変個引数テンプレートを使用してください。

class DelayedCaller
{
public:
  template<typename... Args>
  static DelayedCaller* setup(void (functionPtr*)(Args...), Args&&... args)
  {
    return new DelayedCaller(std::bind(functionPtr, std::forward<Args>(args)...));
  }

  DelayedCaller(const std::function<void()>& f) : f(f) {}

private:
  std::function<void()> f;
};

パブリック コンストラクターは、必要に応じてラムダで初期化する可能性をユーザーに提供します。

于 2013-02-12T13:29:05.530 に答える