Qt-interest Archive, January 2007
Simplified C++ Property using Q_PROPERTY - doable without macro hack?
Message 1 in thread
Hey,
I'm trying to have a C++ property object that can have their properties
manipulated using meta data (at run-time) and came up with what I
thought was a neat little solution using Q_PROPERTY, only to smack
myself in the head when I realized that moc does not do C macro
expansion (in Qt3, and I think in Qt4 as well).
Has anybody figured out a one-liner (or minimal) way of doing something
similar to this?
Here is my solution:
// This property system uses Qt's underlying property system to easily
// have object properties that can be access and modified through meta
data.
#define G_PROPERTY( t_type, name, defaultValue )
\
private:
\
Q_PROPERTY(t_type name READ get_##name WRITE set_##name RESET
reset_##name); \
public:
\
t_type name;
\
t_type get_##name() const { return name; }
\
void set_##name(t_type name) {this->name = name;}
\
void reset_##name(){ name = defaultValue; }
// Example use
class Features : public QObject {
Q_OBJECT;
public:
Features();
G_PROPERTY( bool, hasSomeFeature, false );
G_PROPERTY( bool, hasAnotherFeature, false );
};
//Could set defaults like this
Feature::Feature(){
QMetaObject *m = this->metaObject();
for(int i=0; i<m->numProperties(); i++)
{
bool s = m->property(i)->reset(this); //Set's default value
}
}
This actually works if you change the moc command to do something like
this:
cc -E feature.h | moc -o moc_feature.cpp
but defaulty it does not work because moc does'nt exapnd the G_PROPERTY
macro.
Any ideas/solutions?
--
[ signature omitted ]
Message 2 in thread
Gabe F. Rudy wrote:
> Hey,
>
> I'm trying to have a C++ property object that can have their
> properties manipulated using meta data (at run-time) and came up with
> what I thought was a neat little solution using Q_PROPERTY, only to
> smack myself in the head when I realized that moc does not do C macro
> expansion (in Qt3, and I think in Qt4 as well).
>
> Has anybody figured out a one-liner (or minimal) way of doing
> something similar to this?
>
> Here is my solution:
>
> // This property system uses Qt's underlying property system to easily
> // have object properties that can be access and modified through meta
> data.
> #define G_PROPERTY( t_type, name, defaultValue
> ) \
> private:
> \
> Q_PROPERTY(t_type name READ get_##name WRITE set_##name RESET
> reset_##name); \
> public:
> \
> t_type
> name; \
> t_type get_##name() const { return name;
> } \
> void set_##name(t_type name) {this->name =
> name;} \
> void reset_##name(){ name = defaultValue; }
>
> // Example use
> class Features : public QObject {
> Q_OBJECT;
> public:
> Features();
> G_PROPERTY( bool, hasSomeFeature, false );
> G_PROPERTY( bool, hasAnotherFeature, false );
> };
>
> //Could set defaults like this
> Feature::Feature(){
> QMetaObject *m = this->metaObject();
> for(int i=0; i<m->numProperties(); i++)
> {
> bool s = m->property(i)->reset(this); //Set's default value
> }
> }
>
> This actually works if you change the moc command to do something like
> this:
>
> cc -E feature.h | moc -o moc_feature.cpp
>
While not explicitly stated in the Assistant docs there is a QMAKE_MOC
variable that works just like QMAKE_UIC. It lets you change the
executable line before the options and filename. So there is potential
to override the program that gets called for "moc" in your project.
I suggest making a script that takes in moc's arguements and then calls
cc -E feature.h | moc -o moc_feature.cpp
You might want to define this line in a .pri file that you include() in
your end project files.:
QMAKE_MOC = $(MY_BINS)/myMoc
Don't forget to define MY_BINS or something in your environment
My $0.02,
--Justin
begin:vcard
begin:vcard
fn:Justin Noel
n:Noel;Justin
org:ICS;Engineering
adr:;;54B Middlesex Trpk;Bedford;MA;01730;USA
email;internet:justin@xxxxxxx
title:Sr. Consulting Engineer / Certified Qt Instructor
tel;work:(617) 621-0060
url:http://www.ics.com
version:2.1
end:vcard
Message 3 in thread
>
> While not explicitly stated in the Assistant docs there is a QMAKE_MOC
> variable that works just like QMAKE_UIC. It lets you change the
> executable line before the options and filename. So there is
> potential to override the program that gets called for "moc" in your
> project.
>
> I suggest making a script that takes in moc's arguements and then
> calls cc -E feature.h | moc -o moc_feature.cpp
>
> You might want to define this line in a .pri file that you
> include() in your end project files.:
> QMAKE_MOC = $(MY_BINS)/myMoc
> Don't forget to define MY_BINS or something in your environment
>
> My $0.02,
> --Justin
Yea unfortunately that "cc -E" strategy is not very robust, it comments
out header files which moc would normally intelligently use and place in
the generated files. For example "cc -E" breaks a build with #define(s)
used in default parameters of a moc'd class. Also, it's output isn't
necessarily c++ - causing some other problems at times.
Any other ideas?
--
[ signature omitted ]
Message 4 in thread
Hi,
first of all it's right that the existing Qt property system isn't so smart -
you've to code own getters/setters for each property.
Thus I only use dynamic properties - by just calling setProperty() in a
controctor or in a special init function.
The idea with the G_PROPERTY macro is quite good - but is has a big mistake in
it:
Why do you declare the class members public?
Sorry, but that's no good programming style.
And to the moc problem:
The simplest solution could be (e.g. a perl) script, which parses only your
macro and can be run before the moc. Therefore you've to replace the moc
command by a script which first checks the given files for your macro and then
calls the original moc.
Just one possibility to solve this.
Greetz,
Chris
--
[ signature omitted ]
Message 5 in thread
> Thus I only use dynamic properties - by just calling
> setProperty() in a controctor or in a special init function.
>
That's interesting, I didn't realize you could add properties in a dynamic fashion that way. It doesn't meet my requirements at the moment, but is nice to know.
> The idea with the G_PROPERTY macro is quite good - but is has
> a big mistake in
> it:
> Why do you declare the class members public?
> Sorry, but that's no good programming style.
I actually did that on purpose, as I wanted the property class members accessible from some highly cpu intensive tight loops and I was concerned about speed, not exposing implementation. But honestly, since the getter/setter is inline, I shouldn't be much of a performance hit if any at all. So I think I'll change it to be more like:
#define G_PROPERTY( t_type, name, defaultValue ) \
private: \
Q_PROPERTY(t_type name READ name WRITE set_##name RESET reset_##name); \
t_type _##name; \
public: \
t_type name() const { return _##name; } \
void set_##name(t_type name) {_##name = name;} \
void reset_##name(){ _##name = defaultValue; } \
Btw, is there any great taboo in having variables start with _ in C++, like bool _myVar; I think compilers use the __ prefix in mangling and special things, but does a single underscore prefix cause cross-platform compile issues?
> And to the moc problem:
> The simplest solution could be (e.g. a perl) script, which
> parses only your macro and can be run before the moc.
> Therefore you've to replace the moc command by a script which
> first checks the given files for your macro and then calls
> the original moc.
I came to the same conclusion last night thinking about it. Although I might write the "custom" parser/generator in C/C++ so I can leave a compiled version on all of our build platforms (or in the code repository) so I don't have to worry about having a perl environment lying around in windows etc.
--
[ signature omitted ]
Message 6 in thread
>Btw, is there any great taboo in having variables start with _ in C++, like
>bool _myVar; I think compilers use the __ prefix in mangling and special
>things, but does a single underscore prefix cause cross-platform compile
>issues?
Not really, some use underscore and some hate them. IMHO there are better ways
to give speaking names for member variables - e.g. the hungarian notation:
"Type m_MyVar;"
e.g.:
"bool m_bFlag; unsigned m_uNum; void* m_pPointer;"
The names with prefix "m_" are very often to find and are very easy to
understand when you've to read foreign code.
>>And to the moc problem:
>>The simplest solution could be (e.g. a perl) script, which
>>parses only your macro and can be run before the moc.
>>Therefore you've to replace the moc command by a script which
>>first checks the given files for your macro and then calls
>>the original moc.
>
>I came to the same conclusion last night thinking about it. Although I might
>write the "custom" parser/generator in C/C++ so I can leave a compiled
>version on all of our build platforms (or in the code repository) so I don't
>have to worry about having a perl environment lying around in windows etc.
That's a quite better way.
Have a Nice Weekend!
Chris
--
[ signature omitted ]
Message 7 in thread
Gabe F. Rudy schrieb:
>> ...
> #define G_PROPERTY( t_type, name, defaultValue ) \
> private: \
> Q_PROPERTY(t_type name READ name WRITE set_##name RESET reset_##name); \
> t_type _##name; \
> public: \
> t_type name() const { return _##name; } \
> void set_##name(t_type name) {_##name = name;} \
> void reset_##name(){ _##name = defaultValue; } \
Doesn't Eclipse (IDE) have support for automatically create set/get
methods in the C/C++ mode, once you right-click on a member variable?
And are there really no Visual Studio extensions which do the same? I
would be really surprised. *google* *google* ...
That would make your macro approach superfluous (apart from your
"default value" extension).
Cheers, Oliver
--
[ signature omitted ]
Message 8 in thread
On 26.01.07 17:39:08, Till Oliver Knoll wrote:
> Gabe F. Rudy schrieb:
> >> ...
> > #define G_PROPERTY( t_type, name, defaultValue ) \
> > private: \
> > Q_PROPERTY(t_type name READ name WRITE set_##name RESET reset_##name); \
> > t_type _##name; \
> > public: \
> > t_type name() const { return _##name; } \
> > void set_##name(t_type name) {_##name = name;} \
> > void reset_##name(){ _##name = defaultValue; } \
>
> Doesn't Eclipse (IDE) have support for automatically create set/get
> methods in the C/C++ mode, once you right-click on a member variable?
No, eclipse only has that for Java programs. For C++ projects all you
can do is rename variables, functions and so on. All other refactoring
stuff doesn't exist.
> And are there really no Visual Studio extensions which do the same?
Well don't they have that built-in?
Andreas
--
[ signature omitted ]
Message 9 in thread
Andreas Pakulat schrieb:
> On 26.01.07 17:39:08, Till Oliver Knoll wrote:
>>> ...
>> Doesn't Eclipse (IDE) have support for automatically create set/get
>> methods in the C/C++ mode, once you right-click on a member variable?
> ...
>> And are there really no Visual Studio extensions which do the same?
>
> Well don't they have that built-in?
Hmmm, not that I know of. But I just checked, all that I could find in
Visual Studio 2005 is something called the "Code Snippets Manager". But
the only support VB, Visual C# and Visual J#, no C++. But for C# they
indeed have something which looks like a "set/get-generator":
Encapsulate Field and
Encapsulate Field Set and
Encapsulate Field Get
That's the closest I could find, but nothing for C++.
Have a nice week-end, Oliver
--
[ signature omitted ]
Message 10 in thread
>Btw, is there any great taboo in having variables start with _ in C++, like
bool _myVar; I think compilers use the >__ prefix in mangling and special
things, but does a single underscore prefix cause cross-platform compile
>issues?
Double leading underscores and a capital letter (__D) are reserved but I
think a single
underscore is "reserved for future use". I would tend to use a different
convention. Some
people use trailing underscores for example.
--
[ signature omitted ]