Envolviendo una función C que toma sus argumentos con void * en C ++ [duplicado]

Aug 21 2020

Estoy envolviendo una función C de freeRTOS que crea una tarea y toma sus argumentos con un puntero vacío en C ++. La función se parece un poco a esto:

void createTask(TaskFunction_t taskCode, void * args);

Entonces, a mi entender, para pasar 2 argumentos a la tarea, necesitaría crear una estructura, convertir su dirección en void *, pasarla y luego devolverla al estado original así:

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));
}

¿Cuál sería la forma preferida de envolver esta función para poder pasar un número variable de argumentos de tipos de variables? ¿Debo dejar void * args como argumento o hay algo que se pueda hacer con plantillas o tal vez tuplas para simplificar un poco este proceso?

Respuestas

2 Eric Aug 21 2020 at 06:54

En C ++ 11 en adelante, puede usar algo como

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));

Debe asegurarse de que la vida útil de fla tarea sea más larga (tal como lo haría con su Paramsobjeto).


En realidad, puede evitarlo por std::functioncompleto, ya que:

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)

Nuevamente, es realmente importante que fpermanezca vivo mientras dure su ejecución. No puedes ponerlo en una pila que muere antes de que lo haga la tarea.