c++ - 推导Lambda仿函数的参数包参数

标签 c++ templates lambda closures

我有一个要用于在EventQueue上执行回调的类:

template <class, class>
class Handler;

template <class Fun, class... Args>
class Handler<void(Args...)>
{
public:
    Handler(events::EventQueue &eq, Fun fun) : _eq(eq), _fun(fun)
    {}

    void operator()(Args... args)
    {
        _eq.call(this, &Handler::callInternal, args...);
    }

private:
    events::EventQueue &_eq;
    Fun _fun;

    void callInternal(Args... args)
    {
        _fun(args...);
    }
};
其中EventQueue::call(...)带有对象指针,方法指针以及用于调用方法的参数。
我真的很想用右值lamba表达式实例化Handler类型的对象,例如
makeHandler([](int result) { ... });
我不在乎是否必须使用诸如makeHandler之类的辅助方法来构造Handler。
但是遵循这些原则的方法对我不起作用:
template <class Fun, class... Args>
Handler<Fun, void(Args...)> makeHandlerInternal(events::EventQueue &eq, Fun fun, void (Fun::*)(Args...) const)
{
    return Handler<Fun, void(Args...)>(eq, fun);
}

template <class Fun, class... Args>
Handler<Fun, void(Args...)> makeHandler(events::EventQueue &eq, Fun fun)
{
    return Handler<Fun, void(Args...)>(eq, fun, &Fun::operator());
}
因为Args ...在我将其定义为Fun::operator()接受的参数之前,似乎被推导为空列表。
附带说明:是否真的有很好的资源来增强出现此类问题的模板编程技能?

最佳答案

您的语法几乎是正确的。我看不出将Args...转换为void(Args...)并提出以下解决方案的充分理由:

// This stub is here for the sake of code completeness only
class EventQueue {
public:
    template<class T, class Fun, class... Args>
    void call(T* obj, Fun fun, Args... args) const {
        std::invoke(fun, obj, args...);
    }
};

template<class Fun, class... Args>
class Handler {
public:
    Handler(EventQueue& eq, Fun fun) : eq_(eq), fun_(fun) {}

    void operator()(Args... args) {
        eq_.call(this, &Handler::callInternal, args...);
    }

private:
    EventQueue& eq_;
    Fun fun_;

    void callInternal(Args... args) {
        fun_(args...);
    }
};

template<class Fun, class... Args>
auto makeHandlerImpl(EventQueue& eq, Fun fun, void (Fun::*)(Args...) const) {
    return Handler<Fun, Args...>(eq, fun);
}

template<class Fun>
auto makeHandler(EventQueue& eq, Fun fun) { 
    return makeHandlerImpl(eq, fun, &Fun::operator());
}

EventQueue eq;
auto handler = makeHandler(eq, [](int result) { std::cout << result; });
handler(2020); // prints 2020

或者,您可以从Args...类型中删除Handler,但将operator()用作模板,得到如下所示:
template<class Fun>
class Handler {
public:
    Handler(EventQueue& eq, Fun fun) : eq_(eq), fun_(fun) {}

    template<class... Args>
    void operator()(Args... args) {
        // static_assert(std::is_invocable_v<Fun, Args...>);
        eq_.call(this, &Handler::callInternal<Args...>, args...);
    }

private:
    EventQueue& eq_;
    Fun fun_;

    template<class... Args>
    void callInternal(Args... args) {
        fun_(args...);
    }
};
现在,使用C++ 17 CTAD,您可以简单地编写:
EventQueue eq;
Handler handler(eq, [](int result) { std::cout << result; });
handler(2020);  // prints 2020
没有任何特殊的帮助功能。

关于c++ - 推导Lambda仿函数的参数包参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63151112/

相关文章:

c++ - 为什么默认情况下全局命名空间中没有 C++14 标准定义的文字?

c++ - const char* 类型的无效操作数

c++ - std::string 未正确终止

templates - 了解jsf ui的用途 :composition

java - 如何将其转换为 lambda 表达式?

java - 这里不需要方法引用表达式,编译时错误

c++ - 为什么将 float64 转换为 int32 在 Go 中会给出负数?

c++ - 基类模板实例化取决于派生类构造函数参数类型

c++ - 稍后添加模板函数的特化

c# - 是否可以在 EntityFramework 中将 Select(l=> new{}) 与 SelectMany 一起使用