c++gccvisual-c++clang

Is there an alternative for visual C++ __declspec (property declaration attribute) in clang and gcc?


There is a Microsoft specific extension, which makes it possible to define property getters and setters like this:

// declspec_property.cpp
struct S {
   int i;
   void putprop(int j) {
      i = j;
   }

   int getprop() {
      return i;
   }

   __declspec(property(get = getprop, put = putprop)) int the_prop;
};

int main() {
   S s;
   s.the_prop = 5;
   return s.the_prop;
}

Is there any way to define property declaration attribute with clang or gcc? If I search for __declspec, all I find is __declspec(dllexport), but I am not looking for that.


Solution

  • While C++ does not offer support for smart overridable operators (and there are no gcc extensions for that), the language allows you to implement it using it's existing features.
    The following example (which does not assume to cover all cases!) shows a possible solution using native C++ 11 or higher.
    We could use virtual overrides to override the properties, but that's not how modern smart properties work in other languages such as swift, C# etc, so instead - I'm using lambdas to inject overriding code for setters and getters.

    // The following is by no means a FULL solution!
    #include <functional>
    #include <iostream>
    #include <cassert>
    
    template<typename T> 
    class Property {
    public:
        Property(){}
        operator const T& () const {
            // Call override getter if we have it
            if (getter) return getter();
            return get();
        }
        const T& operator = (const T& other) {
            // Call override setter if we have it
            if (setter) return setter(other);
            return set(other);
        }
        bool operator == (const T& other) const {
            // Static cast makes sure our getter operator is called, so we could use overrides if those are in place
            return static_cast<const T&>(*this) == other;
        }
        // Use this to always get without overrides, useful for use with overriding implementations
        const T& get() const {
            return t;
        } 
        // Use this to always set without overrides, useful for use with overriding implementations
        const T& set(const T& other) {
            return t = other;
        }
        // Assign getter and setter to these properties
        std::function<const T&()> getter;
        std::function<const T&(const T&)> setter;
    private:
        T t;
    };
    
    // Basic usage, no override
    struct Test {
        Property<int> prop;
    };
    
    // Override getter and setter
    struct TestWithOverride {
        TestWithOverride(){
            prop.setter = [&](const int& other){
                std::cout << "Custom setter called" << std::endl;
                return prop.set(other);
            };
            prop.setter = std::bind(&TestWithOverride::setProp,this,std::placeholders::_1);
            prop.getter = std::bind(&TestWithOverride::getProp,this);
        }
        Property<int> prop;
    private:
        const int& getProp() const {
            std::cout << "Custom getter called" << std::endl;
            return prop.get();
        }
        const int& setProp(const int& other){
            std::cout << "Custom setter called" << std::endl;
            return prop.set(other);
        }
    };
    
    int main(int,char**){
        Test t;
        TestWithOverride t1;
        t.prop = 1;
        assert(t.prop == 1);
        t1.prop = 1;
        assert(t1.prop == 1);
        /*
        Expected output:
        1. No aborts on assertions
        2. Text:
        Custom setter called
        Custom getter called
        */
        return 0;
    }
    

    Compile with something like:
    c++ -std=c++11 test.cpp -o test
    Run:
    ./test