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.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…