信号槽的语法糖
Syntax sugar for signal slot
最近我在互联网上搜索了一个好的信号槽库,想知道为什么我们需要如此繁琐的语法来将成员方法连接到信号?
通常我们必须写这样的东西:
mySignal.connect(&MyClassName::myMethodName, this);
或者类似的:
mySignal += std::bind(&MyClassName::myMethodName, this, std::placeholders::_1);
有明显的重复和不必要的打字。在现代C++中,是否有可能以C#方式实现这样的功能:
mySignal += myMethodName
并自动捕获指向成员函数的指针和上下文中的指针?
在现代C++中,有可能以C#的方式实现这样的功能吗?[…]
不,这在C++中是不可能的。获取成员函数地址的语法要求用类名(即&MyClassName::myMethodName
)限定函数名。
如果您不想指定类名,一种可能性是使用lambdas。特别是,如果你能负担得起C++14编译器,通用lambdas允许写:
mySignal.connect([this] (auto x) -> { myMethodName(x) });
遗憾的是,你再也找不到比这更简洁的了。您可以使用默认的lambda捕获来保存一些语法噪音:
mySignal.connect([&] (auto x) -> { myMethodName(x) });
然而,Scott Meyers在他的新书《高效现代C++》中警告了默认lambda捕获模式的陷阱。从可读性的角度来看,与第一个选项相比,我不确定这是否能改善很多。
此外,如果您希望lambda将其参数完美地转发给myMethodName
:,事情很快就会变得尴尬
mySignal.connect([&] (auto&& x) -> { myMethodName(std::forward<decltype(x)>(x)) });
如果你不介意宏(我通常会介意),你可以按照Quentin在回答中的建议,使用基于预处理器的解决方案。然而,在这种情况下,我更喜欢使用完美的转发lambda:
#define SLOT(name)
[this] (auto&&... args) { name (std::forward<decltype(args)>(args)...); }
你可以这样使用:
e.connect(SLOT(foo));
以下是Coliru上的现场演示。
预处理器应该尝试一下吗?
#include <type_traits>
#define CONNECT(method)
connect(&std::remove_pointer_t<decltype(this)>::method, this)
甘蔗的用途如下:
mySignal.CONNECT(myMethodName);
相关文章:
- 1d 智能指针不适用于语法 (*)++
- Qt VTK交互风格的信号到小部件
- 助记符和指向成员语法的指针
- 有人能分解一下这个c++模板的语法吗
- C++避免重复声明的语法是什么
- QMetaObject invokeMethod的基于函数指针的语法
- 如何使用新语法QT5将信号连接到信号?
- QObject::连接不起作用 - 使用函数语法找不到信号
- Qt的新信号/时隙语法问题 - 连接到一个简单的函数
- 禁用 Qt5 代码中的旧(Qt4 样式)信号槽语法
- QT和新的信号槽语法,QApplication::退出主功能外的插槽
- 使用具有新信号槽语法的Qt插件系统在接口类中声明信号
- 在Qt信号和插槽中使用lambda语法并访问传递的参数
- 信号槽的语法糖
- 如何在Qt 5中声明新信号槽语法作为函数参数
- 如何使用新的QObject::连接语法与函数指针将QSslSocket::错误信号连接到插槽
- Qt 插槽和信号语法
- 新的Qt信号语法错误与重载没有这个
- Qt5 信号/时隙语法,带过载信号和 lambda
- QSerialPort 新信号槽语法 没有匹配的成员函数,用于调用"连接"