扣除 Lambda 函子的参数包参数
Deduct Parameter Pack Arguments for Lambda Functor
我有一个 class 想用来在 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(...) 接受对象指针、方法指针和调用方法的参数。
我真的很想用右值兰巴表达式实例化一个 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
或者,您可以从 Handler
类型中删除 Args...
,但将 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
没有任何特殊的辅助函数。
我有一个 class 想用来在 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(...) 接受对象指针、方法指针和调用方法的参数。
我真的很想用右值兰巴表达式实例化一个 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
或者,您可以从 Handler
类型中删除 Args...
,但将 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
没有任何特殊的辅助函数。