本机C ++属性的可移植性 [英] Portability of Native C++ properties

查看:120
本文介绍了本机C ++属性的可移植性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Visual Studio中,有 __ declspec(property) 创建类似于C#的属性。 Borland C ++提供了具有完全相同功能的 __ property 关键字。在C ++ 0x中,提到了一个 implicit 关键字,可以展开以实现相同的功能。



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



我不是寻找替代的属性,需要括号来获取或设置属性,如重载



这是一个在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;
}


解决方案

(我希望)标准C ++ ...

  #include< iostream> 

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

属性(C *实例)
:实例(实例)
{
}

操作符T {
return(instance-> * getter)();
}

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

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

财产& 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_; }

属性< 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<< 不同实例prop / prop assign\\\
;
foo.x = foo2.x;
std :: cout<< 调用接受int参数的函数\\\
;
std :: cout<< square(<< foo.x<<)=< square(foo.x)< \\\
;
return 0;
}

正如你可以从 main 使用是透明的,只要你分配类型 T (这里 int )或隐式可转换到 T 到属性,并且只要在读取时将它们转换回 T
$ b

但是,如果你例如将 foo.x 传递给模板函数,行为会有所不同,因为 foo .x 不是 int 属性< Foo,int,...>



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


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;
}

解决方案

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 << "\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;
}

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.

这篇关于本机C ++属性的可移植性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆