Friday 27 February 2015

Snippet: Class Properties in C++11

Update: I discovered several bugs with the initial implementation, so I've updated this post with a more complete solution.

Properties as seen in Python and C# are a pretty nice language feature, they allow you to have the syntax of accessing a public member variable, yet have that access still go through a getter or setter function.

I have to say I'm not totally sold on RW properties (I feel that if you are intending to change the state of a class, you should be forced to make it clear by calling a setter function) but I like RO properties, they remove the need to call a function to just access a value, and still allow you to check pre/post conditions or log access.

C++ doesn't have properties, if you Google around there's a general consensus that they don't fit the language well. However, I got a bit tired of my game engine's API having an excessive number of function calls. Here's an example:

TextureID rtt = window().new_texture(false);
window().mesh(rect_mesh)->set_texture_on_material(0, rtt);

It would be far nicer to be able to write:

TextureID rtt = window->new_texture(false);
window->mesh(rect_mesh)->set_texture_on_material(0, rtt);

... and still have the control that a getter function provides. So I wrote a Property template class, it looks like this..

template<typename Container, typename T>
class Property {
public:
    Property(Container* _this, T Container::* member):
        this_(_this),
        getter_([member](Container* self) -> T& {
            return self->*member;
        }) {
    }

    Property(Container* _this, T* Container::* member):
        this_(_this),
        getter_([member](Container* self) -> T& {
            return *(self->*member);
        }) {
    }

    Property(Container* _this, std::shared_ptr<T> Container::* member):
        this_(_this),
        getter_([member](Container* self) -> T& {
            return *(self->*member);
        }) {
    }

    Property(Container* _this, std::function<T& (Container*)> getter):
        this_(_this),
        getter_(getter) {

    }

    /*
     *  We can't allow copy construction, because 'this_' will never be initialized
     */
    Property(const Property& rhs) = delete;

    Property operator=(const Property& rhs) {
        assert(this_); //Make sure that this_ was initialized

        getter_ = rhs.getter_;
        // Intentionally don't transfer 'this_'
    }

    inline operator T&() const { return getter_(this_); }
    inline T* operator->() const { return &getter_(this_); }
private:
    Container* this_ = nullptr;
    std::function<T& (Container*)> getter_;
};



Container is the class you are adding the property to, T is the type of the property.

Thanks to C++11 allowing initialization of members in the body of the class, and the awesome syntax of lambdas, we can use the Property template like so:

Property<WindowBase, Watcher> watcher = {
    this, [](const WindowBase* self) -> Watcher& {
        if(!self->watcher_) {
            throw LogicError("Watcher has not been initialized");
        } else {
            return *self->watcher_.get();
        }
    }
};

Or, if you just want to wrap a member variable:

Property<WindowBase, Console> console = { this, &WindowBase::console_ };

Unfortunately we can't override the '.' operator in C++ so we can't get the exact same syntax as C# or Python, but the -> operator is good enough (and as a lot of my engine's accessors return pointers, it actually made things more consistent).

12 comments:

  1. An offer is here for you for free fibromyalgia diet plan.

    ReplyDelete
  2. Different classes posts are here for you. I am also a developer and i can easily understand everything which they provide here. I want to be just stay here where you people can must be show law essay help uk work here and then i help them to bring many changes if your work needed.

    ReplyDelete
  3. C+ language is difficult to learn. Overall learning coding needs much energy and time. I buy dissertation online because I have enrolled in a c+ language course. And I didn't get time for writing a dissertation.

    ReplyDelete
  4. Thanks for the article. it was really helpful and I truly appreciate it. tpe manufacturer Visit the website and learn more about TPE and TPR materials, and manufacturing.

    ReplyDelete
  5. buy cheap assignment online buyassignmentservice.com Having the adaptability to assist an extensive choice of topics, we are confident to provide your necessities flawlessly

    ReplyDelete
  6. we have incredible flutes for sale cheap in Ireland. do visit us and place your order now.

    ReplyDelete
  7. famous movie leather jackets are now available at PLJ in very affordable prices. they have huge collection of bombers, bikers, varsity jackets and much more.

    ReplyDelete
  8. Get forcejackets at 15% off this Valentines day and make the day super special for your partner.If came prints is your vibe than you must check out force leather jackets.

    ReplyDelete
  9. This comment has been removed by the author.

    ReplyDelete
  10. Our service is user-friendly, efficient, and free. You just need to upload your PDF, choose your output format, and download your Word file. Our service will maintain the original quality and appearance of your PDF. Try our service today and discover the power of PDF to Word conversion.
    Visit: https://pdftoword.id/

    ReplyDelete
  11. We offer quality, originality, and affordability for our clients. We also provide free revisions, plagiarism reports, and 24/7 support. Contact us today and get your CIPD assignment done by CIPD Experts.
    cipd assignment help 5co01

    ReplyDelete
  12. Get in touch with Emeriosoft, the best company which provide best services for web design Dubai. Emeriosoft provide IT services all over the UAE at affordable rates online.

    ReplyDelete