Trolltech Home | Qt-interest Home | Recent Threads | All Threads | Author | Date
All threads index page 5

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 ]