Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
460 views
in Technique[技术] by (71.8m points)

visual c++ - Portability of Native C++ properties

In Visual Studio, there is __declspec(property) which creates properties similar to C#. Borland C++ offers the __property keyword with the exact same functionality. In the C++0x, there is mention of a implicit keyword that could be expanded to implement the same functionality. But it didn't make it into the spec.

I am looking for a portable and relatively clean method of declaring syntactically sugared properties that will compile in the latest compilers for Windows, OSX and Linux. I am not concerned with compiler compatibility, just one compiler per platform.

I am not looking for alternatives to properties that require parenthesis to get or set the property, such as overloaded methods separating the getters and setters.

Here is an ideal usage which compiles in Visual Studio 2010:

#define _property(_type, _name, _get, _put) __declspec(property(get=_get, put=_put)) _type _name
#define _property_readonly(_type, _name, _get) __declspec(property(get=_get)) _type _name

class Window
{
public:
    _property_readonly(void*, Handle, GetHandle);
    _property(bool, Visible, GetVisible, SetVisible);

    void* GetHandle();
    bool GetVisible();
    void SetVisible(bool);
}

void main()
{
    Window MainWindow;
    if (!MainWindow.Visible)
        MainWindow.Visible = true;
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

This is something similar to what you are asking and is (I hope) standard C++...

#include <iostream>

template<typename C, typename T, T (C::*getter)(), void (C::*setter)(const T&)>
struct Property
{
    C *instance;

    Property(C *instance)
        : instance(instance)
    {
    }

    operator T () const
    {
        return (instance->*getter)();
    }

    Property& operator=(const T& value)
    {
        (instance->*setter)(value);
        return *this;
    }

    template<typename C2, typename T2,
             T2 (C2::*getter2)(), void (C2::*setter2)(const T2&)>
    Property& operator=(const Property<C2, T2, getter2, setter2>& other)
    {
        return *this = (other.instance->*getter2)();
    }

    Property& operator=(const Property& other)
    {
        return *this = (other.instance->*getter)();
    }
};

//////////////////////////////////////////////////////////////////////////

struct Foo
{
    int x_, y_;

    void setX(const int& x) { x_ = x; std::cout << "x new value is " << x << "
"; }
    int getX() { std::cout << "reading x_
"; return x_; }

    void setY(const int& y) { y_ = y; std::cout << "y new value is " << y << "
"; }
    int getY() { std::cout << "reading y_
"; return y_; }

    Property<Foo, int, &Foo::getX, &Foo::setX> x;
    Property<Foo, int, &Foo::getY, &Foo::setY> y;

    Foo(int x0, int y0)
        : x_(x0), y_(y0), x(this), y(this)
    {
    }
};

int square(int x)
{
    return x*x;
}

int main(int argc, const char *argv[])
{
    Foo foo(10, 20);
    Foo foo2(100, 200);
    int x = foo.x; std::cout << x << "
";
    int y = foo.y; std::cout << y << "
";
    foo.x = 42; std::cout << "assigned!
";
    x = foo.x; std::cout << x << "
";
    std::cout << "same instance prop/prop assign!
";
    foo.x = foo.y;
    std::cout << "different instances prop/prop assign
";
    foo.x = foo2.x;
    std::cout << "calling a function accepting an int parameter
";
    std::cout << "square(" << foo.x << ") = " <<  square(foo.x) << "
";
    return 0;
}

As you can see from main the usage is transparent as long as you are assigning values of type T (here int) or implicitly convertible to T to properties and as long you are converting them back to T values on reading.

Behavior will be different however if you for example pass foo.x to a template function because the type of foo.x is not int but Property<Foo, int, ...> instead.

You can also have problems with non-template functions... calling a function accepting a T value will work fine, however a T& parameter is for example going to be a problem because basically the function is asking a variable to access directly using the address. For the same reason you cannot pass of course the address of a property to a function accepting a T* parameter.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...