布尔逻辑 - 布尔值更改时的 C++ 触发函数

boolean logic - c++ trigger function when bool changes

本文关键字:C++ 函数 布尔值 布尔逻      更新时间:2023-10-16

我有一个不断流式传输的布尔值。当布尔值变为真时,我需要触发一个函数,当布尔值变为假时,我需要触发另一个函数,但每次更改只能触发一次,所以我不能使用 while(true) 循环。

在 c++ 中"监视"值并在它发生变化时触发的最佳方法是什么?

谢谢。

我会通过设置一个flagTrue变量和一个flagFalse变量来解决这个问题。当您遇到第一个 True 时,flagTrue 将从 false 变为 true,并且所有后续的 True 布尔值都将被忽略。同样,当你遇到你的 firat False 时,flagFalse 会从 False 变为 True,并忽略所有跟随的 False 布尔值。此外,当被检查的布尔值从 True 更改为 False 时,您将 flagTrue 更改为 False,在另一种情况下也是如此。
例:

flagTrue = false
flagFalse = false
if (bool == true && flagTrue == false)
{
   // DoSomething
   flagTrue = true;
   flagFalse = false;
}
else if (bool == false && flagFalse == false)
{
   // DoSomething
   flagTrue = false;
   flagFalse = true;
}

我可能会从这样的东西开始:

#include <functional>
#include <atomic>
#include <iostream>
struct trigger
{
  using closure_type = std::function<void()>;
  trigger(closure_type on_set, closure_type on_reset, bool initial_state = false)
  : _state { initial_state }
  , _on_set(std::move(on_set))
  , _on_reset(std::move(on_reset))
  {}
  void set() {
    if (not _state.exchange(true)) {
      _on_set();
    }
  }
  void reset() {
    if (_state.exchange(false)) {
      _on_reset();
    }
  }
  std::atomic<bool> _state;
  std::function<void()> _on_set;
  std::function<void()> _on_reset;
};
void has_set() {
  // you can marshall accross threads here by posting calls to a 
  // queue
  std::cout << __func__ << std::endl;
}
void has_unset() {
  // you can marshall accross threads here by posting calls to a 
  // queue
  std::cout << __func__ << std::endl;
}
int main()
{
  trigger t { has_set, has_unset };
  t.set();
  t.set();
  t.reset();
  t.reset();
}

看看观察者模式。您可以将布尔值包装在帮助程序类中,该类会在设置布尔值时触发事件。

可观察布尔值的示例实现:

#include <vector>
class Observer {
public:
    virtual void valueChanged() = 0;
};
class ObservableBool {
private:
    bool value;
    std::vector<Observer*> observers = std::vector<Observer*>();
public:
    bool getValue() {
        return value;
    }
    bool setValue(bool value) {
        bool changed = (value != this->value);
        this->value = value;
        if(changed) raiseEvent();
    }
    void addObserver(Observer* observer) {
        observers.push_back(observer);
    }
    void removeObserver(Observer* observer) {
        observers.erase(std::find(observers.begin, observers.end, observer));
    }
private:
    void raiseEvent() {
        for (int i = 0; i < observers.size; ++i) {
            observers[i]->valueChanged();
        }
    }
};

这可以得到很大的改进。一个非常好的方法是实现从布尔到布尔的隐式转换(但要小心,重载布尔的"="运算符可能是危险的)。你可以模板化它来支持任意类型而不仅仅是布尔值,你应该使用智能指针而不是原始指针(std::weak_ptr最好),而不是观察者类,你可能应该使用函数指针来正确支持 lambda。如果你做得对,你可以像使用普通布尔值一样使用该类,在设置新值时开销很小。默认情况下,对更改的所有反应都由更改值的线程执行。

派对有点晚了,但如果你只是想把它敲出来(比如测试),这里有一个稍微简单的解决方案:

/**
 * @brief Set a boolean variable.
 * @param b Pointer to the boolean variable.
 * @param value Set to this value.
 * @return Returns if the value was to be changed.
 */
bool set(bool* b, bool value)
{
    // if b isn't going to change
    if (*b == value) return false;
    // if b is going to change
    else
    {
        *b = value;
        return true;
    }
}
/**
 * @brief A possible implementation
 */
int main()
{
    bool my_variable = false;
    while(true)
    {
        // Set my_variable and flag it if it changed
        bool changed = set(&my_variable, some_function());
        // check for changed
        if (changed)
        {
            // ...
        }
    }
}

这似乎比实现布尔包装类、触发器和观察者模式要少一些。