从成员函数签名中自动推导lambda参数
Automatically deduce lambda arguments from member function signature
通常,我使用lambda函数为第三方库设置对成员函数的回调。例如:
setCallback([this](auto&& ...x) { handleCallback(std::forward<decltype(x)>(x)...); });
现在我有一个带有重载函数的库来设置回调,这使得这一行不明确:
#include <functional>
#include <iostream>
class Library
{
public:
typedef std::function<void (int)> IntFunction;
typedef std::function<void (int, int)> IntIntFunction;
void setCallback(IntFunction f) { f_int_ = f; }
void setCallback(IntIntFunction f) { f_int_int_ = f; }
void callCallback(int a, int b) {
if (f_int_) f_int_(a);
if (f_int_int_) f_int_int_(a, b);
}
private:
IntFunction f_int_;
IntIntFunction f_int_int_;
};
class MyClass
{
public:
MyClass() {
//lib.setCallback([this](auto&& ...x) { handleCallback(std::forward<decltype(x)>(x)...); });
lib.setCallback([this](int a, int b) { handleCallback(a, b); });
}
void handleCallback(int a, int b) {
std::cout << "handleCallback: " << a << ", " << b << std::endl;
}
Library lib;
};
int main()
{
MyClass myclass;
myclass.lib.callCallback(2, 3);
return 0;
}
有没有一种方法可以从handleCallback
函数中自动推导出正确的参数,以避免lambda中的函数参数重复?
您可以为此创建函数:
class MyClass
{
template <typename Ret, typename ...Args>
void setCallback(Ret (MyClass::*member)(Args...) /*const*/) {
lib.setCallback([=](Args...args)
{
(this->*member)(std::forward<decltype(args)>(args)...);
});
}
public:
MyClass() { setCallback(&MyClass::handleCallback); }
void handleCallback(int a, int b) {
std::cout << "handleCallback: " << a << ", " << b << std::endl;
}
Library lib;
};
演示
诀窍是正确地提升函数,尤其是返回类型表达式,因为它将启用SFINAE,使std::function
构造函数能够检测lambda是否能够被调用:
lib.setCallback([this](auto&& ...x) ->
decltype(void(handleCallback(std::forward<decltype(x)>(x)...))) {
handleCallback(std::forward<decltype(x)>(x)...);
}
);
实例
您也可以转发无异常:
lib.setCallback([this](auto&& ...x)
noexcept(noexcept(handleCallback(std::forward<decltype(x)>(x)...)))
-> decltype(void(handleCallback(std::forward<decltype(x)>(x)...))) {
handleCallback(std::forward<decltype(x)>(x)...);
}
);
在这一点上,唯一明智的方法是使用宏:
#define RETURNS(...) noexcept(noexcept(__VA_ARGS__))
-> decltype((__VA_ARGS__)) {
return __VA_ARGS__;
}
并像这样使用:
lib.setCallback([this](auto&& ...x) RETURNS(handleCallback(std::forward<decltype(x)>(x)...)));
实例
根据给出的答案,我构建了这个函数:
#include <type_traits>
#include <utility>
template <typename TClass, typename TRet, typename ...Args>
auto getLambda(TClass *instance, TRet (TClass::*member)(Args...))
{
if constexpr (std::is_void<TRet>::value)
return [=](Args...args){ (instance->*member)(std::forward<decltype(args)>(args)...); };
else
return [=](Args...args){ return (instance->*member)(std::forward<decltype(args)>(args)...); };
}
它可以这样使用:
lib.setCallback(getLambda(this, &MyClass::handleCallback));
演示
现在我用它来替换我以前使用的lambda函数(如问题所示(,因为它提高了可读性。
相关文章:
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 使用自动推导的 lambda 参数作为常量表达式
- 如何参数化用作另一个 lambda 参数的 lambda
- 有没有办法根据 lambda 参数返回类型部分专用化我的模板化函数?
- 从成员函数签名中自动推导lambda参数
- Clang声称通用lambda参数的constexpr成员不是constexpr
- 如果我的模板类型首先以lambda参数而发生,则MSVC会引起一个奇怪的错误
- 继承类中没有匹配的泛型委托作为 lambda 参数
- 为什么在lambda参数中不允许自动
- 如何定义通用 lambda 参数的模板参数?
- 在 QGraphicsScene 中拖动 QPixmap:如何避免 lambda 参数中不允许'auto'
- variadic模板函数会以相反的顺序调用lambda参数
- 可变模板lambda参数的模板推导
- 嵌套模板功能中的C 0x lambda参数
- 带有 std::函数和 lambda 参数的分段错误
- 从值捕获的变量分配到lambda参数时,GCC编译器分割故障
- 标准::p空气的通用 lambda 参数
- C++ lambda 参数列表
- 我的 lambda 参数真的在阴影我的当地人吗?
- 从常量和引用的角度来看,函数应该如何接受*lambda*参数