2017-02-17 10 views
2

関数ポインタは、どのような引数が前もって提供されているかを知る必要があるため、これを行う方法はわかりません。今後の作業のリストを保持

本質的に私は仕事のリストがほしいです。各エントリは、特定の引数で呼び出される関数です。私。 foo(3, "abcd")を作業リストに追加してから、後でbar(&h)を追加します。つまり、どのような種類の関数が追加されるのかはわからない。

後でこのリストの繰り返しを行い、指定された関数呼び出しを行います。

これは実装できますか?

答えて

2

std::function<void()>表します呼び出すことができ、何も返さないもの。

そこに保存する最も明瞭なものはラムダです。 std::dequeまたはstd::vector - - 。

std::function<void()> f = []{ foo(3, "abcd"); }; 

店は「

我々は彼らのリストを構築することができfと呼ばstd::functionfoo(3, "abcd");を呼び出し、後でそれらを呼び出します。

あなたは[]秒以内にキャプチャしたいものを入れてラムダの状態をキャプチャすることができます:

std::function<void()> g = [h]{ bar(&h); }; 

このコピーがhラムダに、そしてhへのポインタでbarを呼び出します。時には、あなたはhを可変にしたいでしょう:あなたはまた、変数への参照を格納しているラムダを持つことができます

std::function<void()> g = [h]()mutable{ bar(&h); }; 

。これは生涯責任を負うので危険です.にラムダを保管しておき、それらをコンテナに保管すると、生涯は単純ではないかもしれません。

C++ 14では、式を[]に配置することもできます。

std::function<void()>は値のように動作します。 void()の関数を呼び出すのと同じように、()で呼び出します。

ラムダの代わりにstd::bindを使用することは技術的に可能ですが、std::bindには多くの変わった癖があり、生成されるコードは通常はほとんど分かりません。それをしないでください。

カスタム関数オブジェクトでもこれを行うことができます。

struct custom { 
    std::string s; 
    void operator()() const { 
    foo(3, s); 
    } 
}; 

その後std::function<void()> f = custom{ "abcd" };fのときf()後で3, std::string("abcd")fooを呼び出すだろうと言うもう一つの方法です。

4

あなたはstd::functionとlambda、またはstd::bindを探しています。

std::functionは、任意の呼び出し可能関数のラッパーです。適切な引数でoperator()と呼ぶことができるものを格納することができます。

あなたが格納できるものはlambdaです:あなたは引数と引数を非引数のラムダにカプセル化し、それを呼び出します。

保存できるもう1つの点は、std::bindの結果です。 std::bindは実質的にメタ機能です。関数fと引数を入力として受け取り、その呼び出しによって結果がfの引数で呼び出される関数オブジェクトを返します。

あなたのケースにこれを適用する方法は次のとおりです。一般的なセットアップ:

std::vector<std::function<void()>> workList; 

fillWorkList(workList); 

for (auto& f : workList) 
    f(); 

そして、ここではfillWorkListの2つの可能性のある実装です。 std::bind有するもの:

void fillWorkList(std::vector<std::function<void()>>& workList) 
{ 
    workList.push_back(std::bind(foo, 3, "abcd")); 
    workList.push_back(std::bind(bar, &h)); 
} 

そしてラムダを有するもの:ここ

void fillWorkList(std::vector<std::function<void()>>& workList) 
{ 
    workList.push_back([]() { foo(3, "abcd"); }); 
    workList.push_back([]() { bar(&h); }); 
} 
+0

は、どのように関数の引数としてのfoo(3、「ABCD」)またはバー(&H)を指定するのでしょうか? I.任意の引数を持つ任意の関数 –

+0

@JensJensenコンパイラは、戻り値を渡していると仮定します。私。それは表現を評価するでしょう。呼び出し可能なオブジェクトをパラメータとして渡すには、バインドを使用するかラムダでラップする必要があります。 – wally

+0

@JensJensenそれはこの答えが示すものです。 'std :: bind'から作成するか、ラムダでラップします。あなたが理解できないことを明確にすることはできますか? – Angew

0

add(foo, 3, "abcd")を使用するための可能溶液、using a parameter pack、及びperfect forwardingある:

#include <functional> 
#include <string> 
#include <iostream> 
#include <vector> 
#include <utility> 

void foo(int val, std::string text) { std::cout << val << '\t' << text << '\n'; } 
void bar(int* ptr) { std::cout << *ptr << '\n'; } 

class Worklist { 
public: 
    template <typename ...Args> 
    void add(Args&&... args) { 
     worklist.push_back(std::bind(std::forward<Args>(args)...)); 
    } 

    void do_all() 
    { 
     for(auto& i : worklist) { 
      i(); 
     } 
    } 

    std::vector<std::function<void(void)>> worklist; 
}; 

int main() 
{ 
    int h{9}; 
    Worklist worklist; 
    worklist.add(foo, 3, "abcd"); 
    worklist.add(bar,&h); 
    worklist.do_all(); 
} 
0

std::bindまたはstd::functionを使用せずに、ラムダをタスクとして受け入れるクラスを書くことは可能です。ここで

std::unique_ptrはラムダのそれぞれを格納するために使用されます。

#include <string> 
#include <iostream> 
#include <vector> 
#include <memory> 
#include <utility> 

void foo(int val, std::string text) { std::cout << val << '\t' << text << '\n'; } 
void bar(int* ptr) { std::cout << *ptr << '\n'; } 

class Generic_Callable { 
public: 
    ~Generic_Callable() = default; 
    virtual void call() = 0; 
}; 

template <typename T> 
class MyCallable : public Generic_Callable { 
public: 
    MyCallable(T &&t) : ptr{std::make_unique<T>(std::move(t))} {} 

    void call() override 
    { 
     (*ptr)(); 
    } 

    std::unique_ptr<T> ptr; 
}; 

class Worklist { 
public: 
    template <typename T> 
    void add(T &&t) 
    { 
     worklist.push_back(std::make_unique<MyCallable<T>>(std::move(t))); 
    } 

    void do_all() { 
     for(auto& i : worklist) 
      i->call(); 
    } 

    std::vector<std::unique_ptr<Generic_Callable>> worklist; 
}; 


int main() 
{ 
    int h{9}; 
    Worklist worklist; 
    worklist.add([]() {foo(3, "abcd"); }); 
    worklist.add([&h]() {bar(&h); }); 
    worklist.do_all(); 
} 
関連する問題