The following code compiles (without warnings) on both clang++-2.9 and g++-4.6. However, the g++ binary Seg Faults, while the clang++ binary runs as intended.
What is the proper way to access template class data members through pointers when overloading []?
Here's the code:
#include <iostream>
template <typename T>
class A {
private:
T val1;
T val2;
public:
T& getVal1() { return val1; }
void setVal1(T aVal) { val1 = aVal; }
T& getVal2() { return val2; }
void setVal2(T aVal) { val2 = aVal; }
};
template <typename T>
class B {
private:
A<T>* aPtr;
public:
A<T>* getAPtr() { return aPtr; }
T& operator[](const int& key) {
if(key == 0) { T& res = getAPtr()->getVal1();
return res; }
else { T& res = getAPtr()->getVal2();
return res; }
}
};
int main()
{
B<int> foo;
foo[0] = 1;
int x = foo[0];
std::cout << foo[0] << " " << x << std::endl; // 1 1
}
You are returning a reference to a local variable (res). The reference won't be valid after returning from operator[]. It could be overwritten by other stuff. What really happens is Undefined: that is why compilers are allowed to eat your children or grow a moustache: Undefined Behaviour
You probably want to return by value.
Edit
Since you have a setter, you don't need the reference: See the solution live at http://ideone.com/oxslQ
Note: there was another problem with aPtr not being initialized. I proposed a simple constructor for that. _You might want to initialize this from elsewhere OR you need
assignment and copy constructors
or use a shared_ptr for aPtr
.
#include <iostream>
template <typename T>
class A
{
private:
T val1;
T val2;
public:
T getVal1()
{
return val1;
}
void setVal1(T aVal)
{
val1 = aVal;
}
T getVal2()
{
return val2;
}
void setVal2(T aVal)
{
val2 = aVal;
}
};
template <typename T>
class B
{
private:
A<T>* aPtr;
B(const B&); // TODO , disallow for now
B& operator=(const B&); // TODO , disallow for now
public:
B() : aPtr(new A<T>()) {}
~B() { delete aPtr; }
A<T>* getAPtr()
{
return aPtr;
}
T operator[](const int& key)
{
if(key == 0)
{
T res = getAPtr()->getVal1();
return res;
}
else
{
T res = getAPtr()->getVal2();
return res;
}
}
};
int main()
{
B<int> foo;
foo.getAPtr()->setVal1(1);
int x = foo[0];
std::cout << foo[0] << " " << x << std::endl; // 1 1
}
If you want to return by ref, then your A::getValX() functions should also return by ref, and your res variable inside B::operator should also be T& instead of T:
#include <iostream>
template <typename T>
class A {
private:
T val1;
T val2;
public:
T& getVal1() { return val1; }
void setVal1(T aVal) { val1 = aVal; }
T& getVal2() { return val2; }
void setVal2(T aVal) { val2 = aVal; }
};
template <typename T>
class B {
private:
A<T>* aPtr;
public:
A<T>* getAPtr() { return aPtr; }
T& operator[](const int& key) {
if(key == 0) { T& res = getAPtr()->getVal1();
return res; }
else { T& res = getAPtr()->getVal2();
return res; }
}
};
int main()
{
B<int> foo;
foo[0] = 1;
int x = foo[0];
std::cout << foo[0] << " " << x << std::endl; // 1 1
}
(Note that it will still crash at runtime, since aPtr isn't initialized anywhere.)
Your original code returns a reference to the local variable res, not to A::val1 / A::val2 as you probably intended. If res is a non-reference variable, then it will be a simple copy of the val1 / val2 value, that is only valid for inside the scope (in this case the function) where it was declared. So you need a reference here.
Related
I'm just getting started with Object Oriented Programming. I'm trying to access member function of two different classes within a template function. I have restricted access to member functions based on boolean flag isAggregateElement. For some reason, Compiler throws error stating that there is no such member function.
class descriptor{
public:
int getName(){
return -5;
}
};
class aggregate{
public:
int getDescription() {
return 234;
}
int getUnit(){
return 1;
}
};
template <typename T>
void buildObjectInfo(const T& classMemberType, const bool& isDataInterface){
T baseTypeElement = classMemberType;
bool isAggregateElement = !isDataInterface;
if(isAggregateElement){
cout<<baseTypeElement.getUnit()<<endl;
} else {
cout<<baseTypeElement.getName()<<endl; // Error gets resolved if I remove the else construct
}
}
int main()
{
aggregate a;
descriptor d;
buildObjectInfo<aggregate>(a,false);
return 0;
}
What should I do to access getUnit() without deleting boolean condition (or) removing else construct in the template function ?
Both branches must be valid. Suppose you call buildObjectInfo(d,false), what should happen then?
You can use constexpr if to discard the false branch.
Note that the getters should be const methods. The template argument can be deduced from the function parameter and you do not need the bool:
#include <iostream>
#include <type_traits>
struct descriptor{
int getName() const { return -5; }
};
struct aggregate{
int getDescription() const { return 234; }
int getUnit() const { return 1; }
};
template <typename T>
void buildObjectInfo(const T& t){
if constexpr(std::is_same_v<aggregate,T>) {
std::cout << t.getUnit() << '\n';
} else {
std::cout << t.getName() << '\n';
}
}
int main() {
aggregate a;
descriptor d;
buildObjectInfo(a);
buildObjectInfo(d);
}
However, for only 2 different types an overloaded function is much simpler:
#include <iostream>
struct descriptor{
int getName() const { return -5; }
};
struct aggregate{
int getDescription() const { return 234; }
int getUnit() const { return 1; }
};
void buildObjectInfo(const aggregate& t) {
std::cout << t.getUnit() << '\n';
}
void buildObjectInfo(const descriptor& t) {
std::cout << t.getName() << '\n';
}
int main() {
aggregate a;
descriptor d;
buildObjectInfo(a);
buildObjectInfo(d);
}
As far as I know, this seems to be impossible in a straightforward way. Making the member const makes it const for everyone. I would like to have a read-only property, but would like to avoid the typical "getter". I'd like const public, mutable private. Is this at all possible in C++?
Currently all I can think of is some trickery with templates and friend. I'm investigating this now.
Might seem like a stupid question, but I have been surprised by answers here before.
A possible solution can be based on an inner class of which the outer one is a friend, like the following one:
struct S {
template<typename T>
class Prop {
friend struct S;
T t;
void operator=(T val) { t = val; }
public:
operator const T &() const { return t; }
};
void f() {
prop = 42;
}
Prop<int> prop;
};
int main() {
S s;
int i = s.prop;
//s.prop = 0;
s.f();
return i, 0;
}
As shown in the example, the class S can modify the property from within its member functions (see S::f). On the other side, the property cannot be modified in any other way but still read by means of the given operator that returns a const reference to the actual variable.
There seems to be another, more obvious solution: use a public const reference member, pointing to the private, mutable, member. live code here.
#include <iostream>
struct S {
private:
int member;
public:
const int& prop;
S() : member{42}, prop{member} {}
S(const S& s) : member{s.member}, prop{member} {}
S(S&& s) : member(s.member), prop{member} {}
S& operator=(const S& s) { member = s.member; return *this; }
S& operator=(S&& s) { member = s.member; return *this; }
void f() { member = 32; }
};
int main() {
using namespace std;
S s;
int i = s.prop;
cout << i << endl;
cout << s.prop << endl;
S s2{s};
// s.prop = 32; // ERROR: does not compile
s.f();
cout << s.prop << endl;
cout << s2.prop << endl;
s2.f();
S s3 = move(s2);
cout << s3.prop << endl;
S s4;
cout << s4.prop << endl;
s4 = s3;
cout << s4.prop << endl;
s4 = S{};
cout << s4.prop << endl;
}
I like #skypjack's answer, but would have written it somehow like this:
#include <iostream>
template <class Parent, class Value> class ROMember {
friend Parent;
Value v_;
inline ROMember(Value const &v) : v_{v} {}
inline ROMember(Value &&v) : v_{std::move(v)} {}
inline Value &operator=(Value const &v) {
v_ = v;
return v_;
}
inline Value &operator=(Value &&v) {
v_ = std::move(v);
return v_;
}
inline operator Value& () & {
return v_;
}
inline operator Value const & () const & {
return v_;
}
inline operator Value&& () && {
return std::move(v_);
}
public:
inline Value const &operator()() const { return v_; }
};
class S {
template <class T> using member_t = ROMember<S, T>;
public:
member_t<int> val = 0;
void f() { val = 1; }
};
int main() {
S s;
std::cout << s.val() << "\n";
s.f();
std::cout << s.val() << "\n";
return 0;
}
Some enable_ifs are missing to really be generic to the core, but the spirit is to make it re-usable and to keep the calls looking like getters.
This is indeed a trickery with friend.
You can use curiously recurring template pattern and friend the super class from within a property class like so:
#include <utility>
#include <cassert>
template<typename Super, typename T>
class property {
friend Super;
protected:
T& operator=(const T& val)
{ value = val; return value; }
T& operator=(T&& val)
{ value = val; return value; }
operator T && () &&
{ return std::move(value); }
public:
operator T const& () const&
{ return value; }
private:
T value;
};
struct wrap {
wrap() {
// Assign OK
prop1 = 5; // This is legal since we are friends
prop2 = 10;
prop3 = 15;
// Move OK
prop2 = std::move(prop1);
assert(prop1 == 5 && prop2 == 5);
// Swap OK
std::swap(prop2, prop3);
assert(prop2 == 15 && prop3 == 5);
}
property<wrap, int> prop1;
property<wrap, int> prop2;
property<wrap, int> prop3;
};
int foo() {
wrap w{};
w.prop1 = 5; // This is illegal since operator= is protected
return w.prop1; // But this is perfectly legal
}
I'm trying to fix a double free or corruption in this class:
struct Holder
{
template <typename T>
Holder(const T& v)
{
_v = new T{};
memcpy(_v, &v, sizeof(T));
_deleter = [this]{
if (_v != nullptr)
{
delete reinterpret_cast<T*>(_v);
_v = nullptr;
}
};
}
template <typename T>
T get()
{
T t;
memcpy(&t, _v, sizeof(T));
return t;
}
~Holder()
{
std::cout << "~Holder() " << std::endl;
_deleter();
}
private:
void* _v;
std::function<void()> _deleter;
};
The goal of this class is to Hold a value of a particular type, like boost::any. So I'm trying to understand the mechanism to safely deallocate all memory.
Probably this line of code:
delete reinterpret_cast<T*>(_v);
doesn't do what I expect ...
**** After Suggestions ****
I've rewrite the code using comment suggestions and adding a move constructor
struct Holder
{
template <typename T>
Holder(const T& v)
{
std::cerr << "create " << N << std::endl;
_v = new T(v);
_deleter = [this]{
if (_v != nullptr)
{
std::cerr << "deleter " << N << std::endl;
delete reinterpret_cast<T*>(_v);
_v = nullptr;
}
};
}
Holder(Holder&& rs)
{
_v = rs._v;
_deleter = std::move(rs._deleter);
rs._deleter = []{}; //usefull to avoid a bad function call
}
template <typename T>
T get() const
{
return *reinterpret_cast<T*>(_v);
}
~Holder()
{
//std::cout << "~Holder() " << N << std::endl;
_deleter();
}
private:
void* _v;
std::function<void()> _deleter;
};
Now seems work but I have to manage others corner case :)
Probably the best solution is to use boost::any:
struct Holder
{
template <typename T>
Holder(const T& v)
{
_v = v;
}
template <typename T>
T get()
{
return boost::any_cast<T>(_v);
}
private:
boost::any _v;
};
But I'am trying to understand how it coudl works without it.
This is my last version:
struct Holder
{
template <typename T>
Holder(const T& v)
{
std::cerr << "create " << N << std::endl;
_v = new T(v);
_deleter = [](void* ptr){
if (ptr != nullptr)
{
std::cerr << "deleter " << std::endl;
delete reinterpret_cast<T*>(ptr);
}
};
_builder = [](void* &dest, void* src){
dest = new T(*reinterpret_cast<T*>(src));
};
}
Holder(const Holder& rs)
{
std::cerr << "copy constr" << std::endl;
if (this != &rs)
{
rs._builder(_v, rs._v);
_deleter = rs._deleter;
_builder = rs._builder;
}
}
Holder(Holder&& rs)
{
std::cerr << "move constr" << std::endl;
if (this != &rs)
{
_v = rs._v;
_deleter = std::move(rs._deleter);
_builder = std::move(rs._builder);
rs._deleter = [](void*){};
}
}
Holder& operator=(const Holder& rs)
{
std::cerr << "copy operator" << std::endl;
if (this != &rs)
{
rs._builder(_v, rs._v);
_deleter = rs._deleter;
_builder = rs._builder;
}
return *this;
}
Holder& operator=(Holder&& rs)
{
std::cerr << "move operator" << std::endl;
if (this != &rs)
{
_v = rs._v;
_deleter = std::move(rs._deleter);
_builder = std::move(rs._builder);
rs._deleter = [](void*){};
}
return *this;
}
template <typename T>
T get() const
{
return *reinterpret_cast<T*>(_v);
}
~Holder()
{
//std::cout << "~Holder() " << N << std::endl;
_deleter(_v);
}
private:
void* _v;
std::function<void(void* ptr)> _deleter;
std::function<void(void* &, void* src)> _builder;
};
Don't reimplement the horse.
using pvoid_holder = std::unique_ptr<void, std::function<void(void*)>>
template<class T>
pvoid_holder pvoid_it( T* t ) {
return { t, [](void* v){ if (v) delete static_cast<T*>(v); } };
}
Now store a pvoid_holder in your Holder class. It will handle memory lifetime for you.
You could use a naked pvoid_holder, but it might have a richer interface than you want (for example, it will allow the stored pointer to be changed without changing the deleter).
You can also replace std::function with void(*)(void*) for a marginal performance gain.
Here is a random idea. I still don't like it though. The whole idea behind this design is bad.
template <typename T>
struct Holder
{
public:
Holder(T const& v)
{
new (&m_v) T(v);
}
T const& get() const
{
return reinterpret_cast<T const&>(m_v);
}
T& get()
{
return reinterpret_cast<T&>(m_v);
}
~Holder()
{
std::cout << "~Holder() " << std::endl;
get().~T();
}
private:
char m_v[sizeof(T)];
};
This class doesn't do the same as yours anymore, ie it can't store arbitrary types in a std::vector<Holder> but only the same type (std::vector<Holder<Foo>>). A comment was too small to contain this code though and I wanted to show a better looking syntax for what you're playing with ;).
That being said, the only way you can do what you're trying to do is when you add a second layer for the reference counting. Ie, you replace your void* _v with something that resembles shared_ptr but which doesn't call delete when the count reaches zero but calls deleter (which therefore should be stored inside this new class). In fact your class looks mostly like this new class, except that you should make it non-copyable and provide reference counting (ie through boost::intrusive_ptr). Then Holder can be a wrapper around that that is copyable.
Probably this line of code: delete reinterpret_cast<T*>(_v); doesn't do what I expect ...
Not exactly. Your types are likely using a default copy ctor; this copies your data pointer _v, and your deleter. So when both objects destruct, both deleters trigger, causing the data to be deleted twice. (Side note--you shouldn't name variables starting with _; such identifiers are reserved for implementations).
Here's what it takes to do type erasure properly, assuming I've no bugs in it. A better way would be to stick to using boost::any.
#include <utility>
struct EmptyType {}; // Thrown if unexpectedly empty
struct InvalidType {}; // Thrown if Holder(T) but get<U>.
struct Holder
{
Holder()
: data_()
, deleter_(e_deleter)
, copier_(e_copier)
, typetag_()
{
}
template<typename T>
Holder(const T& t)
: data_(erase_cast(new T))
, deleter_(deleter<T>)
// Need to explicitly carry T's copy behavior
// because Holder's default copy ctor isn't going to
, copier_(copier<T>)
// You need some way to protect against getting
// an Orange out of a Holder that holds an Apple.
, typetag_(id<T>())
{
}
Holder(const Holder& rhs)
: data_(rhs.copy())
, deleter_(rhs.deleter_)
, copier_(rhs.copier_)
, typetag_(rhs.typetag_)
{
}
template<typename T>
T get()
{
if (!data_) throw EmptyType();
T rv(fetch<T>());
return rv;
}
Holder(Holder&& rhs)
: data_()
, copier_(rhs.copier_)
, deleter_(rhs.deleter_)
, typetag_(rhs.typetag_)
{
std::swap(data_, rhs.data_);
}
~Holder()
{
destroy();
}
private:
// Reinterpret_cast wrappers labeled semantically
template<typename T>
static void* erase_cast(T* t) { return reinterpret_cast<void*>(t); }
template<typename T>
static T* unerase_cast(void* t) { return reinterpret_cast<T*>(t); }
// Return a data copy
void* copy() const { return copier_(data_); }
// Return const reference to data
template<typename T>
const T& fetch() {
if (typetag_!=id<T>()) throw InvalidType();
return *unerase_cast<T>(data_);
}
// Destroy data
void destroy() { deleter_(data_); data_=0; }
// ==== Type erased copy semantics ===
void*(*copier_)(void*);
template<typename T>
static void* copier(void* v) {
return erase_cast<T>(new T(*unerase_cast<T>(v)));
}
static void* e_copier(void*) { return 0; }
// ==== Type erased delete semantics ===
void(*deleter_)(void*);
template<typename T>
static void deleter(void* v) {
delete unerase_cast<T>(v);
}
static void e_deleter(void*) {}
// ==== Type protection using tagging (could also use typeid)
static int makenewid() { static int i=0; return i++;}
template<typename T>
static int id() { static int i=makenewid(); return i; }
// Type erased data
void* data_;
// Type erased tag
int typetag_;
};
...and here is some test/demo code:
#include <iostream>
#include <vector>
#define FAIL() std::cout << "Fail" << std::endl; return 1
int foos=0;
struct Foo { Foo(){++foos;} Foo(const Foo&){++foos;} ~Foo(){--foos;} };
int bars=0;
struct Bar { Bar(){++bars;} Bar(const Bar&){++bars;} ~Bar(){--bars;} };
int main() {
{
std::vector<Holder> v;
Foo fx,fy,fz; Bar ba,bb;
v.push_back(fx); v.push_back(fy); v.push_back(fz);
v.push_back(ba); v.push_back(ba); v.push_back(bb);
v.push_back(Holder());
try {
Foo y = v[2].get<Foo>();
}
catch (EmptyType&) { FAIL(); }
catch (InvalidType&) { FAIL(); }
try {
Foo y = v[4].get<Foo>();
FAIL();
}
catch (EmptyType&) { FAIL(); }
catch (InvalidType&) { }
try {
Foo y = v[6].get<Foo>();
FAIL();
}
catch (EmptyType&) { }
catch (InvalidType&) { FAIL(); }
}
if (foos||bars) { FAIL(); }
std::cout << "Pass" << std::endl;
}
Test results:
$ ./a.exe
Pass
I wonder how to hide a real property field (not make it private or public but force to use setters and getters) and provide him with simple setter and getter. So I wonder how to create api like:
private:
Property( int my_a);
public:
Property( int my_b);
...
{
set_my_a(1);
cout << get_my_a() << endl;
// my_a = 13; // will cause compiler error
...
How to create such thing via Boost preprocessor?
Do you really need to use boost preprocessor?
you have a solution without boost below:
// property.h
#include <stdio.h>
#define property(type) struct : public Property <type>
template <typename T>
class Property
{
protected:
T value;
public:
virtual T get() {
return value;
}
virtual void set(T new_value) {
value = new_value;
}
};
usage example:
// test.cpp
#include "property.h"
class Test {
public:
property(int) {} a;
property(int) {
int get() {
return value * 10;
}
} b;
property(int) {
void set(int x) {
value = x * 200;
}
} c;
property(int) {
int get() {
return value * 3000;
}
void set(int x) {
value = x * 443;
}
} d;
};
main()
{
Test t;
printf("i\ta\tb\tc\td\t\n");
for (int i=0; i<10; i++) {
t.a.set(i);
t.b.set(i);
t.c.set(i);
t.d.set(i);
printf("%i\t%i\t%i\t%i\t%i\n", i, t.a.get(), t.b.get(), t.c.get(), t.d.get());
}
}
The wikipedia solution in http://en.wikipedia.org/wiki/Property_(programming)#C.2B.2B is good but needs a minimal modification to become useful, because without the protected statement you cant write your own getters and setters.
#include <iostream>
template <typename T>
class property {
protected:
T value;
public:
T & operator = (const T &i) {
::std::cout << i << ::std::endl;
return value = i;
}
operator T const & () const {
return value;
}
};
struct Bar {
property <bool> alpha;
struct :public property <int> {
int & operator = (const int &i) {
::std::cout << "new setter " << i << ::std::endl;
return value = i;
}
} bravo;
};
main()
{
Bar b;
b.alpha = false;
b.bravo = (unsigned int) 1;
}
You can change a little more if you want:
#include <iostream>
#define SETTER(type) public: type& operator=(const type new_value)
#define GETTER(type) public: operator type const & () const
template <typename T>
class Property {
protected:
T value;
public:
T & operator = (const T &i) {
::std::cout << i << ::std::endl;
return value = i;
}
template <typename T2> T2 & operator = (const T2 &i) {
::std::cout << "T2: " << i << ::std::endl;
T2 &guard = value;
throw guard; // Never reached.
}
operator T const & () const {
return value;
}
};
struct Bar {
Property <bool> alpha;
struct:Property <int> {
SETTER(int) {
value = new_value * 1000;
::std::cout << "new method " << new_value << ::std::endl;
return value;
}
GETTER(int) {
return value/1000;
}
} bravo;
};
main()
{
Bar b;
b.alpha = false;
b.bravo = (unsigned int) 1;
::std::cout << b.bravo << ::std::endl;
}
Rather than rewrite an example of the implementation, this is the link for one on Wikipedia: http://en.wikipedia.org/wiki/Property_(programming)#C.2B.2B
This basically forces the property to be accessed through getter/setter methods. The upgrade you would need to get your desired effect is the ability to pass functors to these properties. There are plenty of ideas on implementing these; the best approach I cannot advise and depends on your developmental needs. Personally, it feels like over engineering and prefer to just use Pimpl to hide my private details and just provide the getters/setters explicitly.
My use is pretty complicated. I have a bunch of objs and they are all passed around by ptr (not reference or value unless its an enum which is byval). At a specific point in time i like to call CheckMembers() which will check if each member has been set or is null. By default i cant make it all null because i wouldnt know if i set it to null or if it is still null bc i havent touch it since the ctor.
To assign a variable i still need the syntax to be the normal var = p; var->member = new Type;. I generate all the classes/members. So my question is how can i implement a property like feature where i can detect if the value has been set or left as the default?
I am thinking maybe i can use C++ with CLR/.NET http://msdn.microsoft.com/en-us/library/z974bes2.aspx but i never used it before and have no idea how well it will work and what might break in my C++ prj (it uses rtti, templates, etc).
Reality (edit): this proved to be tricky, but the following code should handle your requirements. It uses a simple counter in the base class. The counter is incremented once for every property you wish to track, and then decremented once for every property that is set. The checkMembers() function only has to verify that the counter is equal to zero. As a bonus, you could potentially report how many members were not initialized.
#include <iostream>
using namespace std;
class PropertyBase
{
public:
int * counter;
bool is_set;
};
template <typename T>
class Property : public PropertyBase
{
public:
T* ptr;
T* operator=(T* src)
{
ptr = src;
if (!is_set) { (*counter)--; is_set = true; }
return ptr;
}
T* operator->() { return ptr; }
~Property() { delete ptr; }
};
class Base
{
private:
int counter;
protected:
void TrackProperty(PropertyBase& p)
{
p.counter = &counter;
counter++;
}
public:
bool checkMembers() { return (counter == 0); }
};
class OtherObject : public Base { }; // just as an example
class MyObject : public Base
{
public:
Property<OtherObject> x;
Property<OtherObject> y;
MyObject();
};
MyObject::MyObject()
{
TrackProperty(x);
TrackProperty(y);
}
int main(int argc, char * argv[])
{
MyObject * object1 = new MyObject();
MyObject * object2 = new MyObject();
object1->x = new OtherObject();
object1->y = new OtherObject();
cout << object1->checkMembers() << endl; // true
cout << object2->checkMembers() << endl; // false
delete object1;
delete object2;
return 0;
}
There are a number of ways to do this, with varying tradeoffs in terms of space overhead. For example, here's one option:
#include <iostream>
template<typename T, typename OuterClass>
class Property
{
public:
typedef void (OuterClass::*setter)(const T &value);
typedef T &value_type;
typedef const T &const_type;
private:
setter set_;
T &ref_;
OuterClass *parent_;
public:
operator value_type() { return ref_; }
operator const_type() const { return ref_; }
Property<T, OuterClass> &operator=(const T &value)
{
(parent_->*set_)(value);
return *this;
}
Property(T &ref, OuterClass *parent, setter setfunc)
: set_(setfunc), ref_(ref), parent_(parent)
{ }
};
struct demo {
private:
int val_p;
void set_val(const int &newval) {
std::cout << "New value: " << newval << std::endl;
val_p = newval;
}
public:
Property<int, demo> val;
demo()
: val(val_p, this, &demo::set_val)
{ }
};
int main() {
demo d;
d.val = 42;
std::cout << "Value is: " << d.val << std::endl;
return 0;
}
It's possible to get less overhead (this has up to 4 * sizeof(void*) bytes overhead) using template accessors - here's another example:
#include <iostream>
template<typename T, typename ParentType, typename AccessTraits>
class Property
{
private:
ParentType *get_parent()
{
return (ParentType *)((char *)this - AccessTraits::get_offset());
}
public:
operator T &() { return AccessTraits::get(get_parent()); }
operator T() { return AccessTraits::get(get_parent()); }
operator const T &() { return AccessTraits::get(get_parent()); }
Property &operator =(const T &value) {
AccessTraits::set(get_parent(), value);
return *this;
}
};
#define DECL_PROPERTY(ClassName, ValueType, MemberName, TraitsName) \
struct MemberName##__Detail : public TraitsName { \
static ptrdiff_t get_offset() { return offsetof(ClassName, MemberName); }; \
}; \
Property<ValueType, ClassName, MemberName##__Detail> MemberName;
struct demo {
private:
int val_;
struct AccessTraits {
static int get(demo *parent) {
return parent->val_;
}
static void set(demo *parent, int newval) {
std::cout << "New value: " << newval << std::endl;
parent->val_ = newval;
}
};
public:
DECL_PROPERTY(demo, int, val, AccessTraits)
demo()
{ val_ = 0; }
};
int main() {
demo d;
d.val = 42;
std::cout << "Value is: " << (int)d.val << std::endl;
return 0;
}
This only consumes one byte for the property struct itself; however, it relies on unportable offsetof() behavior (you're not technically allowed to use it on non-POD structures). For a more portable approach, you could stash just the this pointer of the parent class in a member variable.
Note that both classes are just barely enough to demonstrate the technique - you'll want to overload operator* and operator->, etc, as well.
Here's my temporary alternative. One that doesn't ask for constructor parameters.
#include <iostream>
#include <cassert>
using namespace std;
template <class T>
class Property
{
bool isSet;
T v;
Property(Property&p) { }
public:
Property() { isSet=0; }
T operator=(T src) { v = src; isSet = 1; return v; }
operator T() const { assert(isSet); return v; }
bool is_set() { return isSet; }
};
class SomeType {};
enum SomeType2 { none, a, b};
class MyObject
{
public:
Property<SomeType*> x;
Property<SomeType2> y;
//This should be generated. //Consider generating ((T)x)->checkMembers() when type is a pointer
bool checkMembers() { return x.is_set() && y.is_set(); }
};
int main(int argc, char * argv[])
{
MyObject* p = new MyObject();
p->x = new SomeType;
cout << p->checkMembers() << endl; // false
p->y = a;
cout << p->checkMembers() << endl; // true
delete p->x;
delete p;
}