├── README ├── example ├── browser │ └── browser.cc └── graphicsview │ └── graphicsview.cc ├── src ├── property.h ├── property_qobject.h └── qobject_wrappers.h └── test └── test.cc /README: -------------------------------------------------------------------------------- 1 | Small property bindings prototype. 2 | See http://woboq.com/blog/property-bindings-in-cpp.html 3 | 4 | Browse The source using the code browser: 5 | http://woboq.com/blog/property-bindings-in-cpp/code/ 6 | -------------------------------------------------------------------------------- /example/browser/browser.cc: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2013 Olivier Goffart 2 | http://woboq.com/blog/property-bindings-in-cpp.html 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 5 | associated documentation files (the "Software"), to deal in the Software without restriction, 6 | including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 8 | subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all copies or substantial 11 | portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 14 | NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 16 | OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #include "property.h" 21 | #include "qobject_wrappers.h" 22 | 23 | #include 24 | 25 | 26 | typedef QtWrapper::Widget Widget; 27 | typedef QtWrapper::Label Label; 28 | typedef QtWrapper::LineEdit LineEdit; 29 | typedef QtWrapper::Label PushButton; 30 | 31 | struct WebView : QtWrapper::Widget { 32 | template WebView(Args &&...args) : QtWrapper::Widget(std::forward(args)...) { 33 | 34 | //Because the property don't have a NOTIFY signals :-( 35 | title.bindToSignal(metaObject()->indexOfSignal("titleChanged(QString)")); 36 | icon.bindToSignal(metaObject()->indexOfSignal("iconChanged()")); 37 | url.bindToSignal(metaObject()->indexOfSignal("urlChanged()")); 38 | } 39 | property_qobject title{ this, "title" }; 40 | property_qobject icon{ this, "icon" }; 41 | property_qobject url { this, "url" }; 42 | }; 43 | 44 | 45 | struct BrowserWindow : Widget { 46 | LineEdit urlBar { this }; 47 | PushButton nextButton { tr("Next") , this }; 48 | PushButton prevButton { tr("Previous") , this }; 49 | WebView webview { this }; 50 | property_qobject windowTitle { this, "windowTitle" }; 51 | property_qobject windowIcon { this, "windowIcon" }; 52 | 53 | ::property margin {10}; 54 | 55 | BrowserWindow() { 56 | urlBar.geometry = [&](){ return QRect(margin, margin, 57 | prevButton.geometry().left() - 2*margin , 58 | urlBar.sizeHint().height()); }; 59 | nextButton.geometry = [&](){ return QRect(QPoint(geometry().width() - 2*margin - nextButton.sizeHint().width(), margin), 60 | nextButton.sizeHint()); }; 61 | prevButton.geometry = [&](){ return QRect(QPoint(nextButton.geometry().x() - prevButton.sizeHint().width() - margin, margin), 62 | prevButton.sizeHint()); }; 63 | 64 | webview.geometry = [&]() { 65 | int x = urlBar.geometry().bottom() + margin; 66 | return QRect(margin, x, width() - 2*margin, geometry().height() - x - margin); }; 67 | 68 | webview.url =[&](){ return urlBar.text(); }; 69 | //urlBar.text =[&](){ return webview.url(); }; //Well , that's a loop 70 | windowTitle = [&]() { return webview.title(); }; 71 | windowIcon = [&]() { return webview.icon(); }; } 72 | }; 73 | 74 | int main(int argc, char **argv) 75 | { 76 | QApplication app(argc,argv); 77 | 78 | BrowserWindow window; 79 | window.show(); 80 | 81 | return app.exec(); 82 | } 83 | 84 | // c++ -std=c++11 -I../../src -lQt5Core -lQt5Gui -lQt5Widgets -lQt5WebKitWidgets -fPIC -I/usr/include/qt ./browser.cc 85 | -------------------------------------------------------------------------------- /example/graphicsview/graphicsview.cc: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2013 Olivier Goffart 2 | http://woboq.com/blog/property-bindings-in-cpp.html 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 5 | associated documentation files (the "Software"), to deal in the Software without restriction, 6 | including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 8 | subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all copies or substantial 11 | portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 14 | NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 16 | OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #include "property.h" 21 | #include "qobject_wrappers.h" 22 | 23 | #include 24 | 25 | typedef QtWrapper::Widget Widget; 26 | typedef QtWrapper::AbstractSlider Slider; 27 | typedef QtWrapper::Widget GraphicsView; 28 | typedef QtWrapper::Label Label; 29 | typedef QtWrapper::LineEdit LineEdit; 30 | 31 | struct GraphicsRectObject : QGraphicsWidget { 32 | // bind the QObject properties. 33 | property_qobject geometry { this, "geometry" }; 34 | property_qobject opacity { this, "opacity" }; 35 | property_qobject rotation { this, "rotation" }; 36 | 37 | // add a color property, with a hook to update when it changes 38 | property_hook color { [this]{ this->update(); } }; 39 | private: 40 | void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget*) override { 41 | painter->setBrush(color()); 42 | painter->drawRect(boundingRect()); 43 | } 44 | }; 45 | 46 | 47 | struct MyWindow : Widget { 48 | LineEdit colorEdit {this}; 49 | 50 | Slider rotationSlider {Qt::Horizontal, this}; 51 | Slider opacitySlider {Qt::Horizontal, this}; 52 | 53 | QGraphicsScene scene; 54 | GraphicsView view {&scene, this}; 55 | GraphicsRectObject rectangle; 56 | 57 | ::property margin {10}; 58 | 59 | MyWindow() { 60 | // Layout the items. Not really as good as real layouts, but it demonstrates bindings 61 | colorEdit.geometry = [&]{ return QRect(margin, margin, 62 | geometry().width() - 2*margin, 63 | colorEdit.sizeHint().height()); }; 64 | rotationSlider.geometry = [&]{ return QRect(margin, 65 | colorEdit.geometry().bottom() + margin, 66 | geometry().width() - 2*margin, 67 | rotationSlider.sizeHint().height()); }; 68 | opacitySlider.geometry = [&]{ return QRect(margin, 69 | rotationSlider.geometry().bottom() + margin, 70 | geometry().width() - 2*margin, 71 | opacitySlider.sizeHint().height()); }; 72 | view.geometry = [&]{ 73 | int x = opacitySlider.geometry().bottom() + margin; 74 | return QRect(margin, x, width() - 2*margin, geometry().height() - x - margin); 75 | }; 76 | 77 | // Some proper default value 78 | colorEdit.text = QString("blue"); 79 | rotationSlider.minimum = -180; 80 | rotationSlider.maximum = 180; 81 | opacitySlider.minimum = 0; 82 | opacitySlider.maximum = 100; 83 | opacitySlider.value = 100; 84 | 85 | scene.addItem(&rectangle); 86 | 87 | // now the 'cool' bindings 88 | rectangle.color = [&]{ return QColor(colorEdit.text); }; 89 | rectangle.opacity = [&]{ return qreal(opacitySlider.value/100.); }; 90 | rectangle.rotation = [&]{ return rotationSlider.value(); }; 91 | } 92 | }; 93 | 94 | int main(int argc, char **argv) 95 | { 96 | QApplication app(argc,argv); 97 | MyWindow window; 98 | window.show(); 99 | return app.exec(); 100 | } 101 | 102 | // c++ -std=c++11 -I../../src -lQt5Core -lQt5Gui -lQt5Widgets -fPIC -I/usr/include/qt ./graphicsview.cc 103 | -------------------------------------------------------------------------------- /src/property.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2013 Olivier Goffart 2 | http://woboq.com/blog/property-bindings-in-cpp.html 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 5 | associated documentation files (the "Software"), to deal in the Software without restriction, 6 | including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 8 | subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all copies or substantial 11 | portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 14 | NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 16 | OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #pragma once 21 | #include 22 | #include 23 | #include 24 | 25 | class property_base 26 | { 27 | /* Set of properties which are subscribed to this one. 28 | When this property is changed, subscriptions are refreshed */ 29 | std::unordered_set subscribers; 30 | 31 | /* Set of properties this property is depending on. */ 32 | std::unordered_set dependencies; 33 | 34 | public: 35 | virtual ~property_base() 36 | { clearSubscribers(); clearDependencies(); } 37 | 38 | // re-evaluate this property 39 | virtual void evaluate() = 0; 40 | 41 | property_base() = default; 42 | property_base(const property_base &other) : dependencies(other.dependencies) { 43 | for (property_base *p : dependencies) 44 | p->subscribers.insert(this); 45 | } 46 | 47 | protected: 48 | /* This function is called by the derived class when the property has changed 49 | The default implementation re-evaluates all the property subscribed to this one. */ 50 | virtual void notify() { 51 | auto copy = subscribers; 52 | for (property_base *p : copy) { 53 | p->evaluate(); 54 | } 55 | } 56 | 57 | /* Derived class call this function whenever this property is accessed. 58 | It register the dependencies. */ 59 | void accessed() { 60 | if (current && current != this) { 61 | subscribers.insert(current); 62 | current->dependencies.insert(this); 63 | } 64 | } 65 | 66 | void clearSubscribers() { 67 | for (property_base *p : subscribers) 68 | p->dependencies.erase(this); 69 | subscribers.clear(); 70 | } 71 | void clearDependencies() { 72 | for (property_base *p : dependencies) 73 | p->subscribers.erase(this); 74 | dependencies.clear(); 75 | } 76 | 77 | /* Helper class that is used on the stack to set the current property being evaluated */ 78 | struct evaluation_scope { 79 | evaluation_scope(property_base *prop) : previous(current) { 80 | current = prop; 81 | } 82 | ~evaluation_scope() { current = previous; } 83 | property_base *previous; 84 | }; 85 | private: 86 | friend struct evaluation_scope; 87 | /* thread_local */ static property_base *current; 88 | }; 89 | 90 | //FIXME move to .cpp file 91 | property_base *property_base::current = 0; 92 | 93 | /** The property class represents a property of type T that can be assigned a value, or a bindings. 94 | When assigned a bindings, the binding is re-evaluated whenever one of the property used in it 95 | is changed */ 96 | template 97 | struct property : property_base { 98 | typedef std::function binding_t; 99 | 100 | property() = default; 101 | property(const T &t) : value(t) {} 102 | property(const binding_t &b) : binding(b) { evaluate(); } 103 | 104 | void operator=(const T &t) { 105 | value = t; 106 | clearDependencies(); 107 | notify(); 108 | } 109 | void operator=(const binding_t &b) { 110 | binding = b; 111 | evaluate(); 112 | } 113 | 114 | //make it possible to initialize directly with lamda without any casts 115 | template property(const B &b, typename std::enable_if::value, int*>::type = nullptr) : property(T(b)) {} 116 | template typename std::enable_if::value>::type operator= (const B &b) { *this=T(b); } 117 | template property(const B &b, typename std::enable_if::value && !std::is_constructible::value, int*>::type = nullptr) : property(binding_t(b)) {} 118 | template typename std::enable_if::value && !std::is_constructible::value>::type operator= (const B &b) { *this=binding_t(b); } 119 | 120 | const T &get() const { 121 | const_cast(this)->accessed(); 122 | return value; 123 | } 124 | 125 | //automatic conversions 126 | const T &operator()() const { return get(); } 127 | operator const T&() const { return get(); } 128 | 129 | void evaluate() override { 130 | if (binding) { 131 | clearDependencies(); 132 | evaluation_scope scope(this); 133 | value = binding(); 134 | } 135 | notify(); 136 | } 137 | 138 | protected: 139 | T value; 140 | binding_t binding; 141 | }; 142 | 143 | template 144 | struct property_hook : property { 145 | typedef std::function hook_t; 146 | typedef typename property::binding_t binding_t; 147 | void notify() override { 148 | property::notify(); 149 | hook(); 150 | } 151 | property_hook(hook_t h) : hook(h) { } 152 | property_hook(hook_t h, const T &t) : property(t), hook(h) { } 153 | property_hook(hook_t h, binding_t b) : property(b), hook(h) { } 154 | using property::operator=; 155 | private: 156 | hook_t hook; 157 | }; 158 | 159 | /** property_wrapper do not own the property, but use a getter and a setter */ 160 | template 161 | struct property_wrapper : property_base { 162 | typedef std::function binding_t; 163 | typedef std::function write_hook_t; 164 | typedef std::function read_hook_t; 165 | explicit property_wrapper(write_hook_t w, read_hook_t r) : write_hook(std::move(w)), read_hook(std::move(r)) { } 166 | 167 | T get() const { 168 | const_cast(this)->accessed(); 169 | return read_hook(); 170 | } 171 | void operator=(const T &t) { 172 | write_hook(t); 173 | notify(); 174 | } 175 | 176 | void operator=(const binding_t &b) { 177 | binding = b; 178 | evaluate(); 179 | } 180 | 181 | T operator()() const { return get(); } 182 | operator T() const { return get(); } 183 | 184 | using property_base::notify; 185 | protected: 186 | void evaluate() override { 187 | if (binding) { 188 | clearDependencies(); 189 | evaluation_scope scope(this); 190 | write_hook(binding()); 191 | } 192 | notify(); 193 | } 194 | private: 195 | const write_hook_t write_hook; 196 | const read_hook_t read_hook; 197 | binding_t binding; 198 | }; 199 | -------------------------------------------------------------------------------- /src/property_qobject.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2013 Olivier Goffart 2 | http://woboq.com/blog/property-bindings-in-cpp.html 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 5 | associated documentation files (the "Software"), to deal in the Software without restriction, 6 | including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 8 | subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all copies or substantial 11 | portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 14 | NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 16 | OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "property.h" 23 | 24 | #include 25 | #include 26 | 27 | class property_qobject_base : public property_base, private QObject { 28 | 29 | QObject *obj; 30 | QMetaProperty prop; 31 | 32 | public: 33 | property_qobject_base(QObject *o, const char *p) : obj(o) { 34 | const QMetaObject *mo = o->metaObject(); 35 | prop = mo->property(mo->indexOfProperty(p)); 36 | int idx = prop.notifySignalIndex(); 37 | if (idx >= 0) 38 | bindToSignal(idx); 39 | } 40 | 41 | void bindToSignal(int signalIndex) { 42 | QMetaObject::connect(obj, signalIndex, this, staticMetaObject.methodCount()); 43 | } 44 | private: 45 | virtual int qt_metacall(QMetaObject::Call c, int idx, void** a) { 46 | idx = QObject::qt_metacall(c, idx, a); 47 | if (idx < 0) 48 | return idx; 49 | notify(); 50 | return idx; 51 | } 52 | 53 | protected: 54 | // virtual void notify() = 0; 55 | QVariant getProperty() { accessed(); return prop.read(obj); } 56 | bool setProperty(const QVariant &v) { return prop.write(obj, v); } 57 | }; 58 | 59 | template class property_qobject : 60 | public property_qobject_base { 61 | 62 | public: 63 | property_qobject(::QObject *o, const char *p) : property_qobject_base(o, p) {} 64 | 65 | typedef std::function binding_t; 66 | 67 | void operator=(const T &t) { 68 | setProperty(QVariant::fromValue(t)); 69 | clearDependencies(); 70 | //notify(); 71 | //return *this; 72 | } 73 | void operator=(const binding_t &b) { 74 | binding = b; 75 | evaluate(); 76 | //return *this; 77 | } 78 | 79 | T get() { 80 | return qvariant_cast(getProperty()); 81 | } 82 | 83 | void evaluate() 84 | { 85 | T data; 86 | { 87 | evaluation_scope scope(this); 88 | data = binding(); 89 | } 90 | setProperty(QVariant::fromValue(data)); 91 | } 92 | 93 | T operator->() { return get(); } 94 | T operator()() { return get(); } 95 | operator T() { return get(); } 96 | 97 | protected: 98 | binding_t binding; 99 | }; 100 | 101 | -------------------------------------------------------------------------------- /src/qobject_wrappers.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2013 Olivier Goffart 2 | http://woboq.com/blog/property-bindings-in-cpp.html 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 5 | associated documentation files (the "Software"), to deal in the Software without restriction, 6 | including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 8 | subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all copies or substantial 11 | portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 14 | NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 16 | OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | 21 | #include "property_qobject.h" 22 | 23 | #include 24 | #include 25 | 26 | namespace QtWrapper { 27 | 28 | template struct Widget : Base { 29 | template Widget(Args &&...args) : Base(std::forward(args)...) {} 30 | property_wrapper geometry{ 31 | [this](const QRect &r){ this->setGeometry(r); }, 32 | [this]() { return this->Base::geometry(); } }; 33 | 34 | private: 35 | virtual bool event(QEvent* e) override { 36 | switch(e->type()) { 37 | case QEvent::Move: 38 | case QEvent::Resize: 39 | geometry.notify(); 40 | break; 41 | default: 42 | break; 43 | } 44 | return Base::event(e); 45 | } 46 | }; 47 | 48 | template struct Label : Widget { 49 | template Label(Args &&...args) : Widget(std::forward(args)...) {} 50 | property_qobject text{ this, "text" }; 51 | }; 52 | 53 | template struct LineEdit : Widget { 54 | template LineEdit(Args &&...args) : Widget(std::forward(args)...) {} 55 | property_qobject text{ this, "text" }; 56 | }; 57 | 58 | 59 | template struct AbstractSlider : Widget { 60 | template AbstractSlider(Args &&...args) : Widget(std::forward(args)...) {} 61 | property_qobject minimum{ this, "minimum" }; 62 | property_qobject maximum{ this, "maximum" }; 63 | property_qobject value{ this, "value" }; 64 | }; 65 | 66 | } 67 | -------------------------------------------------------------------------------- /test/test.cc: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2013 Olivier Goffart 2 | http://woboq.com/blog/property-bindings-in-cpp.html 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 5 | associated documentation files (the "Software"), to deal in the Software without restriction, 6 | including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 8 | subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all copies or substantial 11 | portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 14 | NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 16 | OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | #include 21 | #include "property.h" 22 | 23 | int calculateArea(int width, int height) { 24 | return (width * height) * 0.5; 25 | } 26 | 27 | struct rectangle { 28 | property parent = nullptr; 29 | property width = 150; 30 | property height = 75; 31 | property area = [&]{ return calculateArea(width, height); }; 32 | 33 | property color = [&]{ 34 | if (parent() && area > parent()->area) 35 | return std::string("blue"); 36 | else 37 | return std::string("red"); 38 | }; 39 | }; 40 | 41 | int main() { 42 | rectangle parent; 43 | rectangle child; 44 | child.parent = &parent; 45 | parent.width = 2; 46 | std::cout << child.color() << std::endl; 47 | //outputs "red" 48 | } 49 | 50 | --------------------------------------------------------------------------------