调用模板提供的(静态)函数
Call template provided (static) function
我正在尝试为 freertos 任务创建 C++ 包装器。
这里的挑战是 freertos 需要采用 c 函数指针,如此处所述
https://www.freertos.org/xTaskCreateStatic.html
现在我想到了这个
template<typename Functor_T, uint32_t u32StackSize>
class CFreeRTOS_Task
{
public:
///Constructor
CFreeRTOS_Task(const std::string& strTaskNameArg);
///Destructor
~CFreeRTOS_Task();
private:
///the Name of this task
const std::string strTaskName;
///the task handle
TaskHandle_t task;
///the task control block
StaticTask_t task_tcb;
///is the task currently running (can be accessed from multiple threads => atomic)
std::atomic<bool> bTaskRunning;
///the actual stack
StackType_t stack[u32StackSize] = {};
///the task function to pass to freertos
static void TaskFunction(void* pvParameters);
};
//+++++++++++++++++++++++++ Implementation +++++++++++++++++++++++++++++++++++++++++
template<typename Functor_T, uint32_t u32StackSize>
CFreeRTOS_Task<Functor_T, u32StackSize>::CFreeRTOS_Task(const std::string& strTaskNameArg) :
strTaskName(strTaskNameArg)
{
task = xTaskCreateStatic(
TaskFunction, /* Function that implements the task. */
strTaskName.c_str(), /* Text name for the task. */
u32StackSize, /* Number of indexes in the xStack array. */
(void*)1, /* Parameter passed into the task. */
tskIDLE_PRIORITY,/* Priority at which the task is created. */
stack, /* Array to use as the task's stack. */
&task_tcb); /* Variable to hold the task's data structure. */
bTaskRunning = true;
}
template<typename Functor_T, uint32_t u32StackSize>
CFreeRTOS_Task<Functor_T, u32StackSize>::~CFreeRTOS_Task()
{
if (bTaskRunning)
{
//terminate task...
bTaskRunning = false;
}
}
template<typename Functor_T, uint32_t u32StackSize>
void CFreeRTOS_Task<Functor_T, u32StackSize>::TaskFunction(void* pvParameters)
{
//do some initilisation
for (;;)
{
//call the user provided task function
Functor_T();
osDelay(10);
}
//shutdown this task (common to all freertos tasks)
}
现在我的实例化看起来像这样
///test task function
static void TestTaskFunc();
///Test task instance
static CFreeRTOS_Task<TestTaskFunc,10> testTask("test_task");
static void TestTaskFunc()
{
volatile uint32_t test = 0;
}
但是我遇到了 2 个编译器错误
error: type/value mismatch at argument 1 in template parameter list for 'template<class Functor_T, long unsigned int u32StackSize> class NRTOS_Wrapper::CFreeRTOS_Task'
static CFreeRTOS_Task<TestTaskFunc,10> testTask("test_task");
^
note: expected a type, got 'NRTOS_Wrapper::TestTaskFunc'
error: invalid conversion from 'const char*' to 'int' [-fpermissive]
你能帮我找出我在这里遗漏了什么吗?
CFreeRTOS_Task
的模板类型是指向可调用对象的指针。仅提供 TestTaskFunc
不会推导出类型(即指向函数的指针),相反,您需要 decltype
它。
static CFreeRTOS_Task<decltype(TestTaskFunc), 10> testTask("test_task");
// ^^^^^^^^
按照您编写 class 模板的方式,Functor_T
是 type 而不是 value。有几个地方你被它绊倒了:
static CFreeRTOS_Task<TestTaskFunc,10> testTask("test_task");
在这里,您试图传递一个值,其中 CFreeRTOS_Task
需要一个类型。
template<typename Functor_T, uint32_t u32StackSize>
void CFreeRTOS_Task<Functor_T, u32StackSize>::TaskFunction(void * pvParameters)
{
//do some initilisation
for(;;)
{
//call the user provided task function
Functor_T(); // <---- HERE
osDelay(10);
}
//shutdown this task (common to all freertos tasks)
}
此处您正在值初始化 Functor_T
类型的临时对象,而不是像注释所暗示的那样调用现有的仿函数对象。 Functor_T()()
之类的东西对于函数对象可能有意义,但是如果 Functor_T
是一个简单的函数指针类型(如您的示例),那将没有任何意义。
您实际需要做的似乎是在 class 中存储仿函数类型的 对象 ,然后将指向该对象的指针传递给 TaskFunction
。例如:
template<typename Functor_T, uint32_t u32StackSize>
class CFreeRTOS_Task
{
public:
///Constructor
CFreeRTOS_Task(std::string strTaskNameArg, Functor_T functor);
private:
//...
using Func_T = std::decay_t<Functor_T>;
///the functor to call
Func_T mFunctor;
///the task function to pass to freertos
static void TaskFunction(void* pvParameters);
};
template<typename Functor_T, uint32_t u32StackSize>
CFreeRTOS_Task<Functor_T, u32StackSize>::CFreeRTOS_Task(
std::string strTaskNameArg,
Functor_T functor
)
: strTaskName{std::move(strTaskNameArg)},
mFunctor{std::move(functor)}
{
task = xTaskCreateStatic(
TaskFunction, /* Function that implements the task. */
strTaskName.c_str(), /* Text name for the task. */
u32StackSize, /* Number of indexes in the xStack array. */
&mFunctor, /* The functor to call, passed as a parameter into the task. */
//^^^^^^^^^^ <---- HERE, pass a pointer to the functor as the task arg
tskIDLE_PRIORITY,/* Priority at which the task is created. */
stack, /* Array to use as the task's stack. */
&task_tcb /* Variable to hold the task's data structure. */
);
bTaskRunning = true;
}
template<typename Functor_T, uint32_t u32StackSize>
void CFreeRTOS_Task<Functor_T, u32StackSize>::TaskFunction(void * pvParameters)
{
//do some initilisation
for(;;)
{
//cast the parameter back to a pointer to the correct functor type
Func_T* pFunctor = reinterpret_cast<Func_T*>(pvParameters);
//call the user provided task function
(*pFunctor)();
osDelay(10);
}
//shutdown this task (common to all freertos tasks)
}
然后在您的调用站点,将函子的 type 作为您的 CFreeRTOS_Task
的模板参数,并传递 value 到它的构造函数:
///test task function
static void TestTaskFunc();
///Test task instance
static CFreeRTOS_Task<decltype(TestTaskFunc),10> testTask("test_task", TestTaskFunc);
//^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^
//Pass the type as a template parameter And the value as a constructor parameter
static void TestTaskFunc()
{
volatile uint32_t test = 0;
}
我正在尝试为 freertos 任务创建 C++ 包装器。 这里的挑战是 freertos 需要采用 c 函数指针,如此处所述 https://www.freertos.org/xTaskCreateStatic.html
现在我想到了这个
template<typename Functor_T, uint32_t u32StackSize>
class CFreeRTOS_Task
{
public:
///Constructor
CFreeRTOS_Task(const std::string& strTaskNameArg);
///Destructor
~CFreeRTOS_Task();
private:
///the Name of this task
const std::string strTaskName;
///the task handle
TaskHandle_t task;
///the task control block
StaticTask_t task_tcb;
///is the task currently running (can be accessed from multiple threads => atomic)
std::atomic<bool> bTaskRunning;
///the actual stack
StackType_t stack[u32StackSize] = {};
///the task function to pass to freertos
static void TaskFunction(void* pvParameters);
};
//+++++++++++++++++++++++++ Implementation +++++++++++++++++++++++++++++++++++++++++
template<typename Functor_T, uint32_t u32StackSize>
CFreeRTOS_Task<Functor_T, u32StackSize>::CFreeRTOS_Task(const std::string& strTaskNameArg) :
strTaskName(strTaskNameArg)
{
task = xTaskCreateStatic(
TaskFunction, /* Function that implements the task. */
strTaskName.c_str(), /* Text name for the task. */
u32StackSize, /* Number of indexes in the xStack array. */
(void*)1, /* Parameter passed into the task. */
tskIDLE_PRIORITY,/* Priority at which the task is created. */
stack, /* Array to use as the task's stack. */
&task_tcb); /* Variable to hold the task's data structure. */
bTaskRunning = true;
}
template<typename Functor_T, uint32_t u32StackSize>
CFreeRTOS_Task<Functor_T, u32StackSize>::~CFreeRTOS_Task()
{
if (bTaskRunning)
{
//terminate task...
bTaskRunning = false;
}
}
template<typename Functor_T, uint32_t u32StackSize>
void CFreeRTOS_Task<Functor_T, u32StackSize>::TaskFunction(void* pvParameters)
{
//do some initilisation
for (;;)
{
//call the user provided task function
Functor_T();
osDelay(10);
}
//shutdown this task (common to all freertos tasks)
}
现在我的实例化看起来像这样
///test task function
static void TestTaskFunc();
///Test task instance
static CFreeRTOS_Task<TestTaskFunc,10> testTask("test_task");
static void TestTaskFunc()
{
volatile uint32_t test = 0;
}
但是我遇到了 2 个编译器错误
error: type/value mismatch at argument 1 in template parameter list for 'template<class Functor_T, long unsigned int u32StackSize> class NRTOS_Wrapper::CFreeRTOS_Task'
static CFreeRTOS_Task<TestTaskFunc,10> testTask("test_task");
^
note: expected a type, got 'NRTOS_Wrapper::TestTaskFunc'
error: invalid conversion from 'const char*' to 'int' [-fpermissive]
你能帮我找出我在这里遗漏了什么吗?
CFreeRTOS_Task
的模板类型是指向可调用对象的指针。仅提供 TestTaskFunc
不会推导出类型(即指向函数的指针),相反,您需要 decltype
它。
static CFreeRTOS_Task<decltype(TestTaskFunc), 10> testTask("test_task");
// ^^^^^^^^
按照您编写 class 模板的方式,Functor_T
是 type 而不是 value。有几个地方你被它绊倒了:
static CFreeRTOS_Task<TestTaskFunc,10> testTask("test_task");
在这里,您试图传递一个值,其中 CFreeRTOS_Task
需要一个类型。
template<typename Functor_T, uint32_t u32StackSize>
void CFreeRTOS_Task<Functor_T, u32StackSize>::TaskFunction(void * pvParameters)
{
//do some initilisation
for(;;)
{
//call the user provided task function
Functor_T(); // <---- HERE
osDelay(10);
}
//shutdown this task (common to all freertos tasks)
}
此处您正在值初始化 Functor_T
类型的临时对象,而不是像注释所暗示的那样调用现有的仿函数对象。 Functor_T()()
之类的东西对于函数对象可能有意义,但是如果 Functor_T
是一个简单的函数指针类型(如您的示例),那将没有任何意义。
您实际需要做的似乎是在 class 中存储仿函数类型的 对象 ,然后将指向该对象的指针传递给 TaskFunction
。例如:
template<typename Functor_T, uint32_t u32StackSize>
class CFreeRTOS_Task
{
public:
///Constructor
CFreeRTOS_Task(std::string strTaskNameArg, Functor_T functor);
private:
//...
using Func_T = std::decay_t<Functor_T>;
///the functor to call
Func_T mFunctor;
///the task function to pass to freertos
static void TaskFunction(void* pvParameters);
};
template<typename Functor_T, uint32_t u32StackSize>
CFreeRTOS_Task<Functor_T, u32StackSize>::CFreeRTOS_Task(
std::string strTaskNameArg,
Functor_T functor
)
: strTaskName{std::move(strTaskNameArg)},
mFunctor{std::move(functor)}
{
task = xTaskCreateStatic(
TaskFunction, /* Function that implements the task. */
strTaskName.c_str(), /* Text name for the task. */
u32StackSize, /* Number of indexes in the xStack array. */
&mFunctor, /* The functor to call, passed as a parameter into the task. */
//^^^^^^^^^^ <---- HERE, pass a pointer to the functor as the task arg
tskIDLE_PRIORITY,/* Priority at which the task is created. */
stack, /* Array to use as the task's stack. */
&task_tcb /* Variable to hold the task's data structure. */
);
bTaskRunning = true;
}
template<typename Functor_T, uint32_t u32StackSize>
void CFreeRTOS_Task<Functor_T, u32StackSize>::TaskFunction(void * pvParameters)
{
//do some initilisation
for(;;)
{
//cast the parameter back to a pointer to the correct functor type
Func_T* pFunctor = reinterpret_cast<Func_T*>(pvParameters);
//call the user provided task function
(*pFunctor)();
osDelay(10);
}
//shutdown this task (common to all freertos tasks)
}
然后在您的调用站点,将函子的 type 作为您的 CFreeRTOS_Task
的模板参数,并传递 value 到它的构造函数:
///test task function
static void TestTaskFunc();
///Test task instance
static CFreeRTOS_Task<decltype(TestTaskFunc),10> testTask("test_task", TestTaskFunc);
//^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^
//Pass the type as a template parameter And the value as a constructor parameter
static void TestTaskFunc()
{
volatile uint32_t test = 0;
}