bool改变时的c ++触发函数
c++ trigger function when bool changes
我有一个不断流式传输的布尔值。我需要在 bool 变为 true 时触发一个函数,当 bool 变为 false 时触发另一个函数,但每次更改只触发一次,所以我不能使用 while(true)
循环。
在 c++ 中 'watch' 值并在其更改时触发的最佳方法是什么?
谢谢。
我会通过设置一个 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;
}
看看观察者模式。您可以将布尔值包装在助手 class 中,只要设置布尔值就会触发事件。
可观察布尔值的示例实现:
#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();
}
}
};
这可以改进很多。一个非常好的方法是实现从 bool 到 bool 的隐式转换(但要小心,重载 bool 的 '=' 运算符可能很危险)。您可以将其模板化以支持任意类型而不仅仅是 bool,您应该使用智能指针而不是原始指针(std::weak_ptr
最好)并且您应该使用函数指针而不是 Observer class支持 lambda。如果操作正确,您可以像使用普通布尔值一样使用 class,在设置新值时开销很小。默认情况下,对更改的所有反应都由更改值的线程执行。
我可能会从这样的事情开始:
#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();
}
晚会有点晚了,但如果你只是想解决问题(比如测试),这里有一个稍微简单的解决方案:
/**
* @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)
{
// ...
}
}
}
与实现布尔包装器 类、触发器和观察者模式相比,这似乎有点矫枉过正。
我有一个不断流式传输的布尔值。我需要在 bool 变为 true 时触发一个函数,当 bool 变为 false 时触发另一个函数,但每次更改只触发一次,所以我不能使用 while(true)
循环。
在 c++ 中 'watch' 值并在其更改时触发的最佳方法是什么?
谢谢。
我会通过设置一个 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;
}
看看观察者模式。您可以将布尔值包装在助手 class 中,只要设置布尔值就会触发事件。
可观察布尔值的示例实现:
#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();
}
}
};
这可以改进很多。一个非常好的方法是实现从 bool 到 bool 的隐式转换(但要小心,重载 bool 的 '=' 运算符可能很危险)。您可以将其模板化以支持任意类型而不仅仅是 bool,您应该使用智能指针而不是原始指针(std::weak_ptr
最好)并且您应该使用函数指针而不是 Observer class支持 lambda。如果操作正确,您可以像使用普通布尔值一样使用 class,在设置新值时开销很小。默认情况下,对更改的所有反应都由更改值的线程执行。
我可能会从这样的事情开始:
#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();
}
晚会有点晚了,但如果你只是想解决问题(比如测试),这里有一个稍微简单的解决方案:
/**
* @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)
{
// ...
}
}
}
与实现布尔包装器 类、触发器和观察者模式相比,这似乎有点矫枉过正。