Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/125.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 实现信号(观察者模式):是否需要可变或常量转换?_C++_C++11_Observer Pattern_Signals Slots - Fatal编程技术网

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。将信号想象为对象的一个成员。如果该对象在特定上下文中是常量,则不能简单地连接到该对象的信号,这就需要用户代码放弃一定级别的常量正确性。我不清楚,我可以试着提供我的意思的代码示例。