C ++でvoid *を使用して引数をとるC関数をラップする[重複]

Aug 21 2020

タスクを作成し、C ++のvoidポインターで引数をとるfreeRTOSのC関数をラップしています。関数は次のようになります。

void createTask(TaskFunction_t taskCode, void * args);

したがって、タスクに2つの引数を渡すことを理解するには、構造体を作成し、そのアドレスをvoid *にキャストし、それを渡してから、次のように元の状態にキャストする必要があります。

struct Params
{
    const int a;
    const double b;
};

static void task(void * args)
{
   auto params = *static_cast<Params*>(args);
   // do something with params.a and params.b
}

int main()
{
   Params params{1, 2.2};
   createTask(task, static_cast<void*>(&params));
}

変数タイプの可変数の引数を渡すことができるように、この関数をラップするための好ましい方法は何でしょうか?void * argsを引数として残す必要がありますか、それともこのプロセスを少し単純化するためにテンプレートまたはタプルを使用して実行できることがありますか。

回答

2 Eric Aug 21 2020 at 06:54

C ++ 11以降では、次のようなものを使用できます。

static void call_task(void *args) {
    auto& f = *static_cast<std::function<void()>*>(args);
    f();
}
// note: need this to stay alive!
std::function<void()> f = [&](){
    // Any arguments you like here
    do_whatever(1, 2, 3)
};
CreateTask(call_task, static_cast<void*>(&f));

の存続期間がfタスクの存続期間よりも長くなるようにする必要があります(Paramsオブジェクトの場合と同じように)。


次のようstd::functionに、実際には完全に回避できます。

template<typename Func>
void call_func(void *args) {
    auto& f = *static_cast<Func*>(args);
    f();
}

template<typename Func>
void wrapped_create_task(Func& func) {
    CreateTask(call_func<Func>, static_cast<void*>(&func));
}
// you can still use `std::function` here, but you don't have to.
auto f = [&](){
    // Any arguments you like here
    do_whatever(1, 2, 3)
};

// this works on any object that implements `operator ()`
wrapped_create_task(f)

繰り返しになりますfが、実行中は存続することが非常に重要です。タスクが終了する前に終了するスタックにそれを置くことはできません。