関数ポインタは、どのような引数が前もって提供されているかを知る必要があるため、これを行う方法はわかりません。今後の作業のリストを保持
本質的に私は仕事のリストがほしいです。各エントリは、特定の引数で呼び出される関数です。私。 foo(3, "abcd")
を作業リストに追加してから、後でbar(&h)
を追加します。つまり、どのような種類の関数が追加されるのかはわからない。
後でこのリストの繰り返しを行い、指定された関数呼び出しを行います。
これは実装できますか?
関数ポインタは、どのような引数が前もって提供されているかを知る必要があるため、これを行う方法はわかりません。今後の作業のリストを保持
本質的に私は仕事のリストがほしいです。各エントリは、特定の引数で呼び出される関数です。私。 foo(3, "abcd")
を作業リストに追加してから、後でbar(&h)
を追加します。つまり、どのような種類の関数が追加されるのかはわからない。
後でこのリストの繰り返しを行い、指定された関数呼び出しを行います。
これは実装できますか?
std::function<void()>
表します呼び出すことができ、何も返さないもの。
そこに保存する最も明瞭なものはラムダです。 std::deque
またはstd::vector
- - 。
std::function<void()> f = []{ foo(3, "abcd"); };
店は「
我々は彼らのリストを構築することができf
と呼ばstd::function
でfoo(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
を呼び出すだろうと言うもう一つの方法です。
あなたは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); });
}
は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();
}
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();
}
は、どのように関数の引数としてのfoo(3、「ABCD」)またはバー(&H)を指定するのでしょうか? I.任意の引数を持つ任意の関数 –
@JensJensenコンパイラは、戻り値を渡していると仮定します。私。それは表現を評価するでしょう。呼び出し可能なオブジェクトをパラメータとして渡すには、バインドを使用するかラムダでラップする必要があります。 – wally
@JensJensenそれはこの答えが示すものです。 'std :: bind'から作成するか、ラムダでラップします。あなたが理解できないことを明確にすることはできますか? – Angew