Avvolgere una funzione C che accetta i suoi argomenti con void * in C ++ [duplicato]

Aug 21 2020

Sto avvolgendo una funzione C da freeRTOS che crea un'attività e prende i suoi argomenti con il puntatore void in C ++. La funzione assomiglia un po 'a questa:

void createTask(TaskFunction_t taskCode, void * args);

Quindi, per quanto ne so, per passare 2 argomenti all'attività avrei bisogno di creare una struttura, eseguire il cast del suo indirizzo su void *, passarlo e quindi restituirlo allo stato originale in questo modo:

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

Quale sarebbe il modo preferito di avvolgere questa funzione in modo da poter passare un numero variabile di argomenti di tipi variabili? Dovrei lasciare void * args come argomento o c'è qualcosa che potrebbe essere fatto con modelli o forse tuple per semplificare un po 'questo processo.

Risposte

2 Eric Aug 21 2020 at 06:54

In C ++ 11 in poi, puoi usare qualcosa di simile

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

Devi assicurarti che la durata di fè più lunga di quella dell'attività (proprio come faresti per il tuo Paramsoggetto).


Puoi effettivamente evitare del std::functiontutto, come:

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)

Ancora una volta, è davvero importante che frimanga in vita per tutta la durata della sua esecuzione. Non puoi metterlo su una pila che muore prima che il compito finisca.