繁体   English   中英

信号槽的语法糖

[英]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在他的新书Effective Modern 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);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM