c++ - 信号槽的语法糖

标签 c++ c++11 signals-slots

最近我在互联网上搜索了良好的信号槽库,想知道为什么我们在地球上需要如此繁琐的语法来将成员方法连接到信号?

通常我们必须这样写:

mySignal.connect(&MyClassName::myMethodName, this);

或者像那样:

mySignal += std::bind(&MyClassName::myMethodName, this, std::placeholders::_1);

有明显的重复和不必要的打字。在现代 C++ 中是否有可能以 C# 方式实现此类功能:

mySignal += myMethodName

并自动捕获指向成员函数的指针和来自上下文的 this 指针?

最佳答案

Is it possible in modern C++ to implement such functionality in, for example, C# way? [...]

不,这在 C++ 中是不可能的。获取成员函数地址的语法需要用类名限定函数名(即 &MyClassName::myMethodName)。

如果您不想指定类名,一种可能是使用 lambda。特别是,如果您买得起 C++14 编译器,则通用 lambda 允许编写:

mySignal.connect([this] (auto x) -> { myMethodName(x) });

遗憾的是,没有比这更简洁的了。您可以使用默认的 lambda 捕获来保存一些语法噪音:

mySignal.connect([&] (auto x) -> { myMethodName(x) });

但是,Scott Meyers 在他的新书 Effective Modern C++ 中警告了默认 lambda 捕获模式的缺陷。从可读性的角度来看,与您的第一个选项相比,我不确定这是否有很大改进。

此外,如果您希望 lambda 完美地将其参数转发给 myMethodName,事情很快就会变得尴尬:

mySignal.connect([&] (auto&& x) -> { myMethodName(std::forward<decltype(x)>(x)) });

如果您不介意宏(我通常介意),您可以使用基于预处理器的解决方案 as suggested by Quentin in their answer .但是,在这种情况下,我更愿意使用完美转发的 lambda:

#define SLOT(name) \
        [this] (auto&&... args) { name (std::forward<decltype(args)>(args)...); }

你可以这样使用:

e.connect(SLOT(foo));

这是一个live demo on Coliru .

关于c++ - 信号槽的语法糖,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28398309/

相关文章:

c++ - 在不创建项目的情况下使用eclipse CDT

c++ - 由于右值引用,C++0x 中的 std::swap 是原子的吗?

c++ - 如何知道一个文件被打开了? QT

c++ - 为什么我不能在信号上启动QThread?

qt - 带有元组的 PySide/PyQT 信号和槽?

c++ - 内存位置未处理的异常 bad_alloc

java - 有界基元

c++ - 字符串迭代器和理解函数

c++ - c++中运算符的地址

c++ - g++ 和 clang++ 可变容器的不同行为