C++ 实现信号(观察者模式):是否需要可变或常量转换?
我正在实现我自己的C++ 实现信号(观察者模式):是否需要可变或常量转换?,c++,c++11,observer-pattern,signals-slots,C++,C++11,Observer Pattern,Signals Slots,我正在实现我自己的信号/slot(观察者模式,Qt风格)机制,这样我就可以有一个属性来通知。。。东西这种情况已经改变 我认为C++11提供了使一个非常简洁和功能强大的实现成为可能所必需的一切。我遇到的“问题”是,如果我想“连接”到const对象的信号,我需要signal::connect函数为const,但要修改回调/观察者列表。有两种简单的方法可以解决此问题: const\u cast中的列表connect 使列表可更改 在我看来,两者似乎都喜欢同一件事(以前也有人问过这件事,例如,在中),逻
信号
/slot(观察者模式,Qt风格)机制,这样我就可以有一个属性
来通知。。。东西这种情况已经改变
我认为C++11提供了使一个非常简洁和功能强大的实现成为可能所必需的一切。我遇到的“问题”是,如果我想“连接”到const
对象的信号,我需要signal::connect
函数为const,但要修改回调/观察者列表。有两种简单的方法可以解决此问题:
const\u cast
中的列表connect
const\u cast
/mutable
的真正合理使用
一些我现在掌握的初步代码:
template<typename... ArgTypes>
class signal
{
public:
template<typename Callable>
void connect(Callable&& callback) const
{
std::lock_guard<std::mutex> lock(slots_mutex);
slots.emplace_back(callback);
}
void emit(ArgTypes... arguments) const
{
std::lock_guard<std::mutex> lock(slots_mutex);
for(auto&& callback : slots)
{
callback(arguments...);
}
}
private:
// mutable here allows to connect to a const object's signals
mutable std::vector<std::function<void(ArgTypes...)>> slots;
std::mutex slots_mutex;
};
模板
类信号
{
公众:
模板
无效连接(可调用和回调)常量
{
std::锁和保护锁(插槽和互斥锁);
插槽。回装(回装);
}
void emit(ArgTypes…参数)常量
{
std::锁和保护锁(插槽和互斥锁);
用于(自动&回拨:插槽)
{
回调(参数…);
}
}
私人:
//这里的mutable允许连接到const对象的信号
可变std::向量时隙;
std::互斥插槽\u互斥;
};
注意我还没有测试过这段代码;这只是我当前心态的反映。
mutable
通常是更好的选择
尽可能避免(const
)强制转换,它很容易命中未定义的行为,而mutable
保证不会1)
1
mutable
类成员保证不会转到发出的代码。例如,text
段
有两种简单的方法可以解决此问题:
const\u cast
中的列表connect
实际上有第三个选择(这是一个通用的可能的解决方案,C++没有提供<代码>可变的关键字)-可以将相关数据移出句法对象:
class X
{
mutable int i1_;
// Data pointed to by i2_ semantically belongs to this object
// but doesn't constitute a syntactical part of it so it is not
// subject to const-correctness checks by the compiler.
std::unique_ptr<int> i2_;
public:
void constFunc() const {
i1_ = 123;
*i2_ = 456;
}
};
X类
{
可变int i1_1;;
//i2_u指向的数据在语义上属于此对象
//但它不构成语法的一部分,所以它不是
//由编译器进行常量正确性检查。
std::唯一的ptr i2;
公众:
void constFunc()常量{
i1=123;
*i2=456;
}
};
尽管有这个额外的选项,我仍然同意的是,
mutable
关键字对于这种情况是正确的选择。它以一种标准化的方式明确记录(例如,允许灰色化)该类的概念上的const
操作在技术上可能不是非变异的。例如,当涉及类的const
函数的线程安全时,最好了解这一点。信号::连接确实修改了信号::插槽。所以,我认为你唯一需要做的就是改变你的设计。让signal::connect是可变的,调用方持有可变的signal指针。非测试代码。。。tsk tsk…@Arnav我现在正在写测试,我只需要解决这个设计问题:p.恐怕我不明白为什么信号本身应该暴露const
方法。为什么不让信号的用户决定他们是否希望它是可变的(或不可变的)?@MatthieM。将信号想象为对象的一个成员。如果该对象在特定上下文中是常量,则不能简单地连接到该对象的信号,这就需要用户代码放弃一定级别的常量正确性。我不清楚,我可以试着提供我的意思的代码示例。