Property like features in C++?

后端 未结 3 1561
孤城傲影
孤城傲影 2020-12-16 08:59

My use is pretty complicated. I have a bunch of objs and they are all passed around by ptr (not reference or value unless its an enum which is byval). At a specific point in

3条回答
  •  我在风中等你
    2020-12-16 09:26

    There are a number of ways to do this, with varying tradeoffs in terms of space overhead. For example, here's one option:

    #include 
    
    template
    class Property
    {
    public:
        typedef void (OuterClass::*setter)(const T &value);
        typedef T &value_type;
        typedef const T &const_type;
    private:
        setter set_;
        T &ref_;
        OuterClass *parent_;
    public:
        operator value_type() { return ref_; }
        operator const_type() const { return ref_; }
    
        Property &operator=(const T &value)
        {
            (parent_->*set_)(value);
            return *this;
        }
    
        Property(T &ref, OuterClass *parent, setter setfunc)
            : set_(setfunc), ref_(ref), parent_(parent)
        { }
    };
    
    
    struct demo {
        private:
            int val_p;
            void set_val(const int &newval) {
                std::cout << "New value: " << newval << std::endl;
                val_p = newval;
            }
    
        public:
            Property val;
    
            demo()
                : val(val_p, this, &demo::set_val)
            { }
    };
    
    int main() {
        demo d;
        d.val = 42;
        std::cout << "Value is: " << d.val << std::endl;
        return 0;
    }
    

    It's possible to get less overhead (this has up to 4 * sizeof(void*) bytes overhead) using template accessors - here's another example:

    #include 
    
    
    template
    class Property
    {
    private:
        ParentType *get_parent()
        {
            return (ParentType *)((char *)this - AccessTraits::get_offset());
        }
    public:
        operator T &() { return AccessTraits::get(get_parent()); }
        operator T() { return AccessTraits::get(get_parent()); }
        operator const T &() { return AccessTraits::get(get_parent()); }
        Property &operator =(const T &value) {
            AccessTraits::set(get_parent(), value);
            return *this;
        }
    };
    
    #define DECL_PROPERTY(ClassName, ValueType, MemberName, TraitsName) \
        struct MemberName##__Detail : public TraitsName { \
            static ptrdiff_t get_offset() { return offsetof(ClassName, MemberName); }; \
        }; \
        Property MemberName;
    
    struct demo {
        private:
            int val_;
    
            struct AccessTraits {
                static int get(demo *parent) {
                    return parent->val_;
                }
    
                static void set(demo *parent, int newval) {
                    std::cout << "New value: " << newval << std::endl;
                    parent->val_ = newval;
                }
            };
        public:
            DECL_PROPERTY(demo, int, val, AccessTraits)
    
            demo()
            { val_ = 0; }
    };
    
    int main() {
        demo d;
        d.val = 42;
        std::cout << "Value is: " << (int)d.val << std::endl;
        return 0;
    }
    

    This only consumes one byte for the property struct itself; however, it relies on unportable offsetof() behavior (you're not technically allowed to use it on non-POD structures). For a more portable approach, you could stash just the this pointer of the parent class in a member variable.

    Note that both classes are just barely enough to demonstrate the technique - you'll want to overload operator* and operator->, etc, as well.

提交回复
热议问题