Указатель на функцию-член

У меня есть функция FreeRTOS xTaskCreate, Упрощенная декларация выглядит так

typedef void (*TaskFunction_t)( void* );
unsigned xTaskCreate( TaskFunction_t pxTaskCode, void*params );

И есть два класса:

class Super {
virtual void task(void*params) = 0;
};
class Derived1 : public Super {
virtual void task(void*params){ while(1){ blinkLed(1); delay_ms(333); } }
};
class Derived2 : public Super { ... ;}

В функции init() Я выбираю один из производных классов и создаю его экземпляр. Затем хотите создать задачу

void init(){
Super *obj = condition ? new Derived1 : new Derived2;
xTaskCreate( obj->task ); // WRONG.
}

Upd. Добавить пропущенный void*params в упрощенной декларации xTaskCreate,

2

Решение

TaskFunction_t это просто указатель на функцию — поэтому он не может взять указатель на функцию-член. Только указатель на нормальную функцию. Или статическая функция-член. Или лямбда без захвата. Это последний, которым мы воспользуемся.

Одним из аргументов, которые вы удалили из своей упрощенной декларации, является контекст:

 BaseType_t xTaskCreate(    TaskFunction_t pvTaskCode,
const char * const pcName,
unsigned short usStackDepth,
void *pvParameters,  // <== this one!
UBaseType_t uxPriority,
TaskHandle_t *pxCreatedTask
);

Вы предоставляете Super* в параметрах и предоставить лямбду, которая знает, что с ней делать. Итого:

void init(){
Super *obj = condition ? new Derived1 : new Derived2;
xTaskCreate([](void* o){ static_cast<Super*>(o)->task(); },
..., // other args here
obj,
... // more args
);
}

Обратите внимание, что task() не должен принимать никаких аргументов. void*это контекст, который мы преобразуем в Super*,

7

Другие решения

После нескольких собственных экспериментов с ответами здесь я предпочел этот более простой метод, предоставляющий вызовы объектно-ориентированных функций для задач RTOS.

//These are not full declaration of class IModule which is fully abstarct so //object that are IModule* are always inherited.
protected:
virtual int InitModule() = 0;
virtual bool PreLoop() = 0;
virtual bool DoLoop() = 0;
virtual bool PostLoop() = 0;
virtual bool DoShutdown() = 0;
//Return if this module implementation requires an RTOS task looping.
virtual bool isFreeRTOSTaskRequired() = 0;
private:
TaskHandle_t *moduleLoopTaskHandle;
bool CreateRTOSTask();
static void TaskStart(void* taskStartParameters);
void TaskLoop();
//END OF PARTIAL decleration

bool IModule::CreateRTOSTask()
{
xTaskCreate(IModule::TaskStart, "NAME", 2048, this, tskNO_AFFINITY, moduleLoopTaskHandle);

return true;
}

void IModule::TaskStart(void *taskStartParameters)
{
IModule *moduleObject = (IModule *)taskStartParameters;
moduleObject->TaskLoop();
}

void IModule::TaskLoop()
{
//TODO Buraya ölçüm koyalım ve bir değişkene yazalım
while (true)
{
ESP_LOGD("IModule::TaskLoop", "%s", "I am alive!");
if (!PreLoop())
{
}

if (!DoLoop())
{
}

if (!PostLoop())
{
}
}

vTaskDelete(NULL);
}
0

ОБНОВЛЕНО: см. Ниже.

Как объяснил лучше чем могу Вот, Вы могли бы сойти с рук с этим. Трудно сказать по вашему вопросу, будет ли он охватывать все ваши требования.

typedef void (Super::*TaskFunction_t)( void* );

Дальнейшее чтение

ОБНОВИТЬ:
Я конкретизировал ваш пример, а результаты и код приведены ниже:

XXXXX:~/scratch/member_function_pointer$ bin/provemeright
Condition false
virtual void Derived2::task(void*)
XXXXX:~/scratch/member_function_pointer$ bin/provemeright foo
Condition true because of argument foo
virtual void Derived1::task(void*)

код (все один файл cpp, плохая форма, но подтверждает синтаксис):

#include <iostream>

class Super;
typedef void (Super::*TaskFunction_t)(void*);
unsigned xTaskCreate( TaskFunction_t pxTaskCode, void* params);

bool condition = false;

class Super {
public: virtual void task(void* params) = 0;
};

class Derived1 : public Super {
public: virtual void task(void* params) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
if(params) // Necessary to prevent unused parameter warning
std::cout << "Not Null" << std::endl;
};
};

class Derived2 : public Super {
public: virtual void task(void* params) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
if(params) // Necessary to prevent unused parameter warning
std::cout << "Not Null" << std::endl;
};
};

void init(){
Super *obj = condition ? (Super*)new Derived1 : (Super*)new Derived2;
xTaskCreate( &Super::task , obj);
}

int main(int argc, char **argv)
{
if(argc > 1)
{
std::cout << "Condition true because of argument " << argv[1] << std::endl;
condition = true;
} else {
std::cout << "Condition false" << std::endl;
}
init();
return 0;
}unsigned xTaskCreate( TaskFunction_t pxTaskCode, void* params)
{
Super *obj = (Super*) params;
(obj->*pxTaskCode)(NULL);
return 0;
}

Если вы обеспокоены тем, что синтаксис &Super::task вместо &obj->task, тогда вы не понимаете, как работают виртуальные функции. (Оказывается, что &obj->task синтаксис запрещен ISO C ++, но gcc говорит, что он разрешительный, поэтому вы не должны, но можете заставить его скомпилировать и получить точно такой же результат)

Информация о том, какая виртуальная версия функции для вызова «живет» в объекте, а не в системе типов. (Возможно, можно было бы сформулировать это лучше, открыть для предложений, но я думаю, что это дает общий смысл) Невозможно вызвать функцию-член без объекта, поэтому для того, чтобы использовать указатель на функцию, вам нужно иметь объект для «вызова». Это тип этого объекта, который будет определять, какая виртуальная функция вызывается. Таким образом, приведенный выше код должен достичь того, к чему вы стремитесь, если, конечно, это не обходной способ определения типа объекта, на который указывает obj, и в этом случае это ужасно запутанный способ добиться этого.

Дальнейшее чтение в частности, в ответе «Kerrek SB».

-1
По вопросам рекламы [email protected]