c++ 如何创建一个同时接受函数指针和lambda作为参数的函数?

kh212irz  于 2023-02-01  发布在  其他
关注(0)|答案(1)|浏览(190)

我有以下类,它有一个名为errorHandler的方法,需要使用几个不同的回调:

class IOPin;
class IOPinHandler
{
    IOPinHandler();
    virtual ~IOPinHandler();

    static bool ptrFun(IOPinHandler&) { return true; };

    template<typename T>
    bool init(IOPin& obj, const T& param);

    template<typename HandlerReturn = void, typename ...Args>
    HandlerReturn errorHandler(const GpioStatusCode& code, HandlerReturn(*callback)(IOPinHandler& obj, const Args&...), const Args&... args);

    // Added this overload to support passing lambdas as arguments, 
    // however does not seems to be called
    template<typename HandlerReturn = void, typename ...Args>
    HandlerReturn errorHandler(const GpioStatusCode& code, const std::function<HandlerReturn(IOPinHandler&, const Args&...)>& callback, Args&... args);
};

我可以使用以下内容:

return errorHandler(GpioStatusCode::wrongArgumentsError, &IOPinHandler::ptrFun);

而且代码编译成功,运行如我所期望的那样。
我也可以用下面的方法传递lambda函数:

auto fix = [](IOPinHandler& obj) -> bool 
{
    return true; 
};
return errorHandler(GpioStatusCode::wrongArgumentsError, static_cast<bool(*)(IOPinHandler&)>(fix));

这样,代码也可以成功编译和运行。
但是,如果我在lambda函数中添加capture,代码将无法编译:

auto fix = [&](IOPinHandler& obj) -> bool 
{
    return true; 
};
return errorHandler(GpioStatusCode::wrongArgumentsError, fix);

我得到以下编译时错误:

error: no matching function for call to 'IOPinHandler::errorHandler(GpioStatusCode, IOPinHandler::init<GpioMode>::<lambda(IOPinHandler&)>&)'
   12 |         return errorHandler(GpioStatusCode::wrongArgumentsError, fix);

我想再加一句:

template<typename HandlerReturn = void, typename ...Args>
HandlerReturn errorHandler(const GpioStatusCode& code, const std::function<HandlerReturn(IOPinHandler&, const Args&...)>& callback, Args&... args);

将匹配接收lambda函数作为参数的模板示例化,但事实上,我不得不强制转换不带捕获的lambda,而带捕获的lambda也不起作用,这有点暗示我,只有第一个定义或“errorHandler“被调用。
我的推理是对的吗?我怎么能通过呢?

编辑:完整代码。

#include <functional>

class IOPin;

class IOPinHandler
{

    public:
        template<typename ...T>
        IOPinHandler(const T&... args);
        virtual ~IOPinHandler(); 

        static bool ptrFun(IOPinHandler&);

        template<typename T>
        bool init(const T& param);

        template<typename HandlerReturn = void, typename ...Args>
        HandlerReturn errorHandler(const int& code, HandlerReturn(*callback)(IOPinHandler& obj, const Args&...), const Args&... args);

        // Added this overload to support passing lambdas as arguments, 
        // however does not seems to be called
        template<typename HandlerReturn = void, typename ...Args>
        HandlerReturn errorHandler(const int& code, const std::function<HandlerReturn(IOPinHandler&, const Args&...)>& callback, Args&... args);
};

template<typename ...T>
IOPinHandler::IOPinHandler(const T&... args)
{
    (init(args),...);
}

bool IOPinHandler::ptrFun(IOPinHandler&)
{
    return true;
}

template<typename T>
bool IOPinHandler::init(const T& param)
{
    // Compiles with no problem
    // return errorHandler(1, &IOPinHandler::ptrFun); 

    // Compiles with no problem
    // auto fix = [](IOPinHandler& obj) -> bool 
    // {
    //    return true; 
    // };
    // return errorHandler(1, static_cast<bool(*)(IOPinHandler&)>(fix));

    // Does not compiles
    auto fix = [&](IOPinHandler& obj) -> bool 
    {
        return true; 
    };
    return errorHandler(1, fix);    
}

int main(void)
{
    IOPinHandler a(1,'c',true);
    return 0;
}
euoag5mw

euoag5mw1#

如果我理解正确的话,您不需要任何成员函数重载,甚至不需要std::function
您可以将Callable作为模板参数,并让编译器为您推导它的类型。

template<typename Callable, typename... Args>
auto errorHandler(const GpioStatusCode& code, Callable callback, Args&&... args)
  // -> decltype(callback(args...))---> if compiler does not support C++14 or later
{
    // if needed within the function body
    using HandlerReturn = decltype(callback(args...)); 
    // ... do something
    return callback(std::forward<Args>(args)...);
}

Live Demo

相关问题