【问题标题】:Call template provided (static) function调用模板提供的(静态)函数
【发布时间】:2020-09-30 10:27:42
【问题描述】:

我正在尝试为 任务创建 C++ 包装器。 这里的挑战是 freertos 需要采用 函数指针,如此处所述 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]

你能帮我找出我在这里缺少什么吗?

【问题讨论】:

    标签: freertos c c++ c++11 templates function-pointers freertos


    【解决方案1】:

    您编写类模板的方式,Functor_Ttype 而不是 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 是一个简单的函数指针类型(如您的示例),则没有任何意义。


    您实际上需要做的似乎是在您的类中存储一个仿函数类型的对象,然后将指向该对象的指针传递给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;
    }
    

    Live Demo

    【讨论】:

    • 感谢您 2 的快速回答 :) 不幸的是,这并不完全有效。我想``` (*Functor_T)();``` 实际上应该是(*pFunctor)(); 对吧?但是静态转换失败invalid static_cast from type 'void*' to type 'void (*)()' Functor_T* pFunctor = static_cast&lt;Functor_T*&gt;(pvParameters); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~你能帮我吗?
    • 糟糕,已修复。那应该是 reinterpret_cast 而不是 static_cast(*pFunctor)() 而不是 (*Functor_T)()
    • 我还错过了 decltype(TestTaskFunc)void() 而不是 void(*)()。添加了using Func_T = std::decay_t&lt;Functor_T&gt; 并切换到存储Func_T 来处理这个问题。再次更新,现在有一个工作演示。
    【解决方案2】:

    CFreeRTOS_Task 的模板类型是一个指向可调用对象的指针。只提供TestTaskFunc 不会推断出类型(即指向函数的指针),而是需要decltype

    static CFreeRTOS_Task<decltype(TestTaskFunc), 10> testTask("test_task");
    //                    ^^^^^^^^
    

    【讨论】:

      猜你喜欢
      • 2017-06-10
      • 1970-01-01
      • 1970-01-01
      • 2011-12-28
      • 1970-01-01
      • 1970-01-01
      • 2017-04-26
      • 2016-12-30
      • 1970-01-01
      相关资源
      最近更新 更多