Properties with non standard C++ (REALLY SORRY ABOUT THAT)

V

Vincent RICHOMME

Hi,

first I would like to apologize about my question because usually I hate
specific implementation but in this case I really would like an answer.
Besides my example is an example of what's not to be done but I am aware
of that.
Don't loose time tell me that I should use standard implementation and
consider my question as theoretical.
So I am using Microsoft compiler and I have a class with lots of methods
with get and set :


class foo
{
public:
....

LPCTSTR GetName();
void SetName(LPCTSTR Value);
A GetABC();

void SetABC(A Value);
A GetABC();

void SetDEF(B Value);
B GetDEF();

....

};

So I would like to mix preprocessor tricks(it's bad I know) and template :
I am thinkinf of something like :


DECLARE_PROPERTY(Name, LPCTSTR);
DECLARE_PROPERTY(ABC, A);
DECLARE_PROPERTY(DEF, B);


and after maybe
Property.Name = L"Vincent";
LPCTSTR tszName = Property.Name;




And here is what I have done for now :

template<class TYPE>
struct Property
{
TYPE m_Type;

TYPE Get()
{
g_pClient->Get ...( m_Type); // FILL BY MACRO
return TYPE;
}

void Set()
{
g_pClient->Set ...( m_Type); // FILL BY MACRO

}

__declspec(property(get = Get, put = Put)) TYPE the_prop;
};

// template specialization for C strings
template<>
struct Property<LPCTSTR>
{
... blabla
}..




I am sur there is something to do with all that but I still cannot find
the way.


I would try something like

DECLARE_PROPERTY(PropName, TYPE) \
template<class TYPE> \
struct Property \
{ \
TYPE m_Type; \
TYPE Get() \
{ \
g_pClient->Get ...( m_Type); \
return TYPE; \
} \

void Set() \
{ \
g_pClient->Set ...( m_Type); \
} \
__declspec(property(get = Get, put = Put)) TYPE PropName; \
}; \

typedef something ...


Please give me your feedback


//------------------------ MS property ---------------------//
/ declspec_property.cpp
struct S {
int i;
void putprop(int j) {
i = j;
}

int getprop() {
return i;
}

__declspec(property(get = getprop, put = putprop)) int the_prop;
};

int main() {
S s;
s.the_prop = 5;
return s.the_prop;
}
 
V

Victor Bazarov

Vincent said:
Hi,

first I would like to apologize about my question because usually I
hate specific implementation but in this case I really would like an
answer. [..]

Is there any reason why you dind't post it to the newsgroup that
specifically caters to the needs of Visual Studio?

V
 
V

Vincent RICHOMME

Victor Bazarov a écrit :
Vincent said:
Hi,

first I would like to apologize about my question because usually I
hate specific implementation but in this case I really would like an
answer. [..]

Is there any reason why you dind't post it to the newsgroup that
specifically caters to the needs of Visual Studio?

V
Yes and a good one : people here have better knowledge of C++ and are
more used to manipulate concept like template, OOP.
When I see people who can write boost class for instance, I must admit
I am impressed and you cannot find people like that on any newsgroup.
 
V

Vincent RICHOMME

Vincent RICHOMME a écrit :
Victor Bazarov a écrit :
Vincent said:
Hi,

first I would like to apologize about my question because usually I
hate specific implementation but in this case I really would like an
answer. [..]

Is there any reason why you dind't post it to the newsgroup that
specifically caters to the needs of Visual Studio?

V
Yes and a good one : people here have better knowledge of C++ and are
more used to manipulate concept like template, OOP.
When I see people who can write boost class for instance, I must admit
I am impressed and you cannot find people like that on any newsgroup.
But if you can give me a more standard approach I am curious.
The problem here is my class has lots of methods with different names
that almost do the same :

class foo
{
public:
....

LPCTSTR GetName();
void SetName(LPCTSTR Value);
A GetABC();

void SetABC(A Value);
A GetABC();

void SetDEF(B Value);
B GetDEF();

....
};
 
V

Vincent RICHOMME

ok I found a solution to my problem.



Vincent RICHOMME a écrit :
Vincent RICHOMME a écrit :
Victor Bazarov a écrit :
Vincent RICHOMME wrote:
Hi,

first I would like to apologize about my question because usually I
hate specific implementation but in this case I really would like an
answer. [..]

Is there any reason why you dind't post it to the newsgroup that
specifically caters to the needs of Visual Studio?

V
Yes and a good one : people here have better knowledge of C++ and are
more used to manipulate concept like template, OOP.
When I see people who can write boost class for instance, I must admit
I am impressed and you cannot find people like that on any newsgroup.
But if you can give me a more standard approach I am curious.
The problem here is my class has lots of methods with different names
that almost do the same :

class foo
{
public:
...

LPCTSTR GetName();
void SetName(LPCTSTR Value);
A GetABC();

void SetABC(A Value);
A GetABC();

void SetDEF(B Value);
B GetDEF();

...
};
 
I

Ian Collins

Vincent said:
Hi,

first I would like to apologize about my question because usually I hate
specific implementation but in this case I really would like an answer.
Besides my example is an example of what's not to be done but I am aware
of that.
Don't loose time tell me that I should use standard implementation and
consider my question as theoretical.
So I am using Microsoft compiler and I have a class with lots of methods
with get and set :
In most cases, getters and setters are a bad design smell. Why
encapsulate something only to break the encapsulation?
 
V

Victor Bazarov

Vincent said:
Vincent RICHOMME a écrit :
Victor Bazarov a écrit :
Vincent RICHOMME wrote:
Hi,

first I would like to apologize about my question because usually I
hate specific implementation but in this case I really would like
an answer. [..]

Is there any reason why you dind't post it to the newsgroup that
specifically caters to the needs of Visual Studio?

V
Yes and a good one : people here have better knowledge of C++ and are
more used to manipulate concept like template, OOP.
When I see people who can write boost class for instance, I must
admit I am impressed and you cannot find people like that on any
newsgroup.
But if you can give me a more standard approach I am curious.
The problem here is my class has lots of methods with different names
that almost do the same :

class foo
{
public:
...

LPCTSTR GetName();
void SetName(LPCTSTR Value);
A GetABC();

void SetABC(A Value);
A GetABC();

void SetDEF(B Value);
B GetDEF();

...
};

I don't know what to recommend you. There is no one "hard and fast"
solution that would be good for all. In many cases separating the
concepts (to reduce the individual number of "properties") is good
enough a way to go:

class hasName {
whatevertypeyoulike name;
public:
LPCTSTR GetName() const;
void SetName(LPCTSTR);
};
...
class foo : public hasName .... {
...
};

(yes

Essentially this employs the "policy" technique (see Alexandrescu,
"Modern C++ Design").

You can also create (and possibly pre-fill) a 'std::map' of all the
named values of your "properties". You then have a slightly smaller
set of functions:

class foo {
public:
boost::any GetProp(LPCTSTR) const;
void SetProp(LPCTSTR, boost::any);
};

There are plenty of other portable solutions, you just need to
search for them. Have you actually tried looking, say, on Google?

V
 
J

Jerry Coffin

Hi,

first I would like to apologize about my question because usually I hate
specific implementation but in this case I really would like an answer.
Besides my example is an example of what's not to be done but I am aware
of that.
Don't loose time tell me that I should use standard implementation and
consider my question as theoretical.
So I am using Microsoft compiler and I have a class with lots of methods
with get and set :

A design with lots of accessors and mutators is usually a sign of a
problematic design -- you're usually better off fixing it than
facilitating it. In particular, this usually signals somebody who's
heard that public variables are bad, but hasn't grasped _why_ they're
bad, so he makes the variables themselves private, then then provides
public access to them via the get and set methods. The result is the
worst of all worlds -- the design is still one of public variables, and
all that's really changed is that the syntax has gotten really ugly.

The variables should be private because the interface should _usually_
be one of the class providing a higher-level abstraction, so clients do
NOT just get and set values. One basic principle is generally as "don't
ask -- tell". The idea is that code outside the class should NOT request
information about the class state before making a modification. e.g.
this would be bad:

some_class x;

if (x.getsomevalue() < 10)
x.setsomeothervalue(12);

Instead, the class itself should contain that intelligence, and the
outside code should just do something like: x.dowhatever(12);

Occassionally, however, you run into something that really makes sense
with an interface with what at least look and act like public variables.
In this case, (at least IMO) get/set methods are the wrong way to go. If
you really want unrestricted access to these variables, then just make
the public. If your get/set methods really do something (typically
range-checking) to assure the values are valid, then you should create
something that looks and acts like a public variable, but gives you the
control you need (e.g. carries out the aforementioned range-checking).

Since range-checking is so common, I've written a small template that
implements it:

#include <exception>
#include <iostream>
#include <functional>

template <class T, class less=std::less<T> >
class bounded {
const T lower_, upper_;
T val_;

bool check(T const &value) {
return less()(value, lower_) || less()(upper_, value);
}

void assign(T const &value) {
if (check(value))
throw std::domain_error("Out of Range");
val_ = value;
}

public:
bounded(T const &lower, T const &upper)
: lower_(lower), upper_(upper) {}

bounded(bounded const &init) { assign(init); }

bounded &operator=(T const &v) { assign(v); return *this; }

operator T() const { return val_; }

friend std::istream &operator>>(std::istream &is, bounded &b) {
T temp;
is >> temp;

if (b.check(temp))
is.setstate(std::ios::failbit);
else
b.val_ = temp;
return is;
}
};

This would be used like:

struct X {
bounded<int> x;
bounded<int> y;

X() : x(1, 100), y(0, 200) {}
};

and now code that uses these can simply treat x and y as public
variables (since they are) but you still have full control to assure
that only valid values are assigned to them. It's also possible to pass
the bounds as template parameters, so those would look like:

bounded<int, 1, 100> x;
bounded<int, 0, 200> y;

But this doesn't work for floating point ranges (OTOH, it has some
advantages, such as making different ranges different types, so
accidentally assigning from one to another is an error -- though an
explicit cast makes it possible when needed).
 
A

abadura

Try out this code:
#include <iostream>
#include <string>

using namespace std;



template<typename class_T, typename T, typename const_reference_T =
const T&> class property {
public:
typedef T value_type;
typedef const_reference_T const_reference_type;
typedef class_T class_type;

typedef const_reference_type (class_type::*get_type)() const;
typedef void (class_type::*set_type)(const_reference_type);
typedef value_type& (class_type::*get_ref_type)();

public:
property(class_type* p_obj, get_type p_get_fun, set_type p_set_fun,
get_ref_type p_get_ref_fun) : m_p_obj(p_obj), m_p_get_fun(p_get_fun),
m_p_set_fun(p_set_fun), m_p_get_ref_fun(p_get_ref_fun) {}

T& operator =(const_reference_type value) {
(m_p_obj->*m_p_set_fun)(value);
return (m_p_obj->*m_p_get_ref_fun)();
}

operator const_reference_type() {
return (m_p_obj->*m_p_get_fun)();
}

private:
class_type* m_p_obj;

get_type m_p_get_fun;
set_type m_p_set_fun;
get_ref_type m_p_get_ref_fun;

};



class example {
public:
example() : width(this, &example::get_width, &example::set_width,
&example::get_ref_width), title(this, &example::get_title,
&example::set_title, &example::get_ref_title), m_width(0), m_title()
{};

property<example, int, int> width;
property<example, string> title;

private:
int m_width;

int get_width() const {
return m_width;
}

void set_width(int width) {
m_width = width;
}

int& get_ref_width() {
return m_width;
}


string m_title;

const string& get_title() const {
return m_title;
}

void set_title(const string& title) {
m_title = title;
}

string& get_ref_title() {
return m_title;
}

};



void test(int val) {
cout << "test(int): " << val << endl;
}

void test(const string& val) {
cout << "test(string): " << val << endl;
}

int main(int, char* []) {
example ex;
cout << "ex.width: " << static_cast<int>(ex.width) << endl;
cout << "ex.title: " << static_cast<const string&>(ex.title) << endl;
ex.width = 1;
ex.title = "title";
cout << "ex.width: " << static_cast<int>(ex.width) << endl;
cout << "ex.title: " << static_cast<const string&>(ex.title) << endl;
test(ex.width);
test(ex.title);
return 0;
}
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

The code compiles and workes fine on GCC (however I do not remebrer
which version) and MS VS 2005.
Note that I pass pointer "this" in constructor - which is not a
good idea to do. However this code does not use this value before the
construction completes so no problem - bu if you want to remove this
you can always allow late initialization of this pointer (but then you
would HAVE to remember to do this).

The idea behind this is to make a tamplate class which will allow
property-like behavior. You must pass some arguments as you can read
from the code. const_reference_T is used to allow the behavior with
basic types where you do not use reference but a simple type.

As you can see using to << operator requires explicit cast. You can
remove this by decalring the operator for property class.

Naturally the class can be easly modified to react on other needs
or to simulate get-only or set-only properties. I think that using
template metaprograming could improve the code. This was just a quick
try to give you some ideas.

Adam Badura
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top