Native C++属性的可移植性

Jos*_*own 27 c++ gcc properties visual-c++ c++11

在Visual Studio中,__declspec(property)创建了与C#类似的属性.Borland C++提供的__property关键字具有完全相同的功能.在C++ 0x中,提到了一个implicit可以扩展以实现相同功能的关键字.但它没有进入规范.

我正在寻找一种可移植且相对干净的方法来声明语法上含糖的属性,这些属性将在最新的Windows,OSX和Linux编译器中编译.我不关心编译器兼容性,每个平台只有一个编译器.

我不是在寻找需要括号来获取或设置属性的属性的替代方法,例如分隔getter和setter的重载方法.

这是在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;
}
Run Code Online (Sandbox Code Playgroud)

650*_*502 27

这与你所要求的类似,是(我希望)标准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 << "\n"; }
    int getX() { std::cout << "reading x_\n"; return x_; }

    void setY(const int& y) { y_ = y; std::cout << "y new value is " << y << "\n"; }
    int getY() { std::cout << "reading y_\n"; 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 << "\n";
    int y = foo.y; std::cout << y << "\n";
    foo.x = 42; std::cout << "assigned!\n";
    x = foo.x; std::cout << x << "\n";
    std::cout << "same instance prop/prop assign!\n";
    foo.x = foo.y;
    std::cout << "different instances prop/prop assign\n";
    foo.x = foo2.x;
    std::cout << "calling a function accepting an int parameter\n";
    std::cout << "square(" << foo.x << ") = " <<  square(foo.x) << "\n";
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

您可以从main使用中看到透明,只要您分配类型T(此处int)的值或隐式转换T为属性,并且只要您将它们转换回T读取值即可.

行为将有所不同,但是如果您传递foo.x给模板函数,因为类型foo.x不是,int而是Property<Foo, int, ...>相反.

您也可能遇到非模板函数的问题...调用接受T值的函数将正常工作,但是T&参数例如会成为一个问题,因为基本上该函数要求变量直接使用该地址进行访问.出于同样的原因,您无法将属性的地址传递给接受T*参数的函数.


sma*_*ipt 7

Clang现在已__declspec(property...)完全实施Microsoft ,并且进行了优化。因此,您可以在所有平台上的c ++中使用属性,并在基于gcc或c99的代码中混合使用。

我已经使用了一年多,并且等待它普遍出现超过五年。

它是用于抽象结构和重构代码的最强大的C ++工具之一。我一直在使用它,以便快速构建结构,然后在性能或重组需要时再进行重构。

它是无价的,我真的不明白为什么C ++标准很久以前没有采用它。但是话又说回来,它们拥有使用c ++和模板的许多复杂而肿的提升方式。

现在,Clang在每个平台上都具有很高的可移植性,以至于拥有此功能非常出色。

内发展(免费或付费版)使用Visual Studio铛几乎是无缝的,你会得到令人难以置信的调试开发工具集,只是让工作在其他的工具集和平台痛苦的对比。

clang现在专门用于我的所有c ++开发。