У меня есть простой класс property<T> с value_changed<T>, который вы можете connect/disconnect, и принимать или запрещать события при вызове value_changed<T>::emit(T). Подумайте о сигнале/слотах Qt на стероидах С++ 11.
Моя следующая задача - предоставить объект, подобный объекту, который состоит из под-свойств. Подумайте, например, о позиции или размере, которые состоят из нескольких значений. Я хотел бы иметь возможность обрабатывать подобъекты как property и дополнительно получать составной сигнал, излучаемый при одновременном изменении нескольких значений. Например. делать
struct
{
property<int> x;
property<int> y;
}
position2d pos{0,0};
// ...
pos = {1,1}; // this should fire x.value_changed, y.value_changed, and pos.value_changed (once!)
Это последнее маленькое слово является ядром проблемы. Я изо всех сил пытаюсь закодировать повторно используемый composite_property, который можно настроить с помощью имен субобъектов (позиция будет получать x, y, но размер получит width/height).
Примечание a property<struct { int x; int y; }> не хватает: изменение x не будет выдавать композитный сигнал value_changed.
Лучшее, что я могу придумать, - это что-то с кучей кода шаблона для подключения/отключения подобъектов при назначении суперобъекту, который является утомительным и идет против принципа DRY.
Я открыт для волшебной магии шаблона, хотя я понимаю, что свободное присвоение переменных (x/y и width/height) сделает хотя бы некоторый код шаблона.
EDIT Для полноты, это шаблон property, который у меня есть сейчас:
template<typename T>
class property
{
public:
using value_type = T;
using reference = std::add_lvalue_reference_t<T>;
using const_reference = std::add_lvalue_reference_t<std::add_const_t<T>>;
using rvalue_reference = std::add_rvalue_reference_t<T>;
property(const_reference value_ = {}) : value(value_) {}
operator const_reference() const { return value; }
property& operator=(const_reference& other)
{
const bool changed = value != other;
value = other;
if(changed)
value_changed.emit(value);
return *this;
}
bool operator==(const_reference other) const { return value == other; }
bool operator!=(const_reference other) const { return value != other; }
bool operator< (const_reference other) const { return value < other; }
bool operator<=(const_reference other) const { return value <= other; }
bool operator> (const_reference other) const { return value > other; }
bool operator>=(const_reference other) const { return value >= other; }
signal<value_type> value_changed;
private:
value_type value;
};
signal немного больше задействован и доступен здесь. В принципе, connect как Qt, за исключением того, что он возвращает объект connection_type, такой как Boost.Signal, который можно использовать для disconnect этого соединения.
Примечание. Я открыт для функции "изменять свойство без изменений", которая обходит сигнал, но только реализует половину того, что мне нужно.