C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Compile-time programming beginner - How to do simple class/c

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
Whitney Kew
Guest





PostPosted: Fri Apr 16, 2004 3:00 pm    Post subject: Compile-time programming beginner - How to do simple class/c Reply with quote



Hello everyone,

I have a situation that seems to scream "compile-time programming" to
me, but I'm still a compile-time programming beginner, and I just
can't see the elegant solution. Having read Alexandrescu's "Modern
C++ Design," I feel like there is in fact an elegant solution! If
someone could give me some help with this, I feel like I could finally
get my feet wet in the weird world of compile-time programming, and
thus grow significantly as a C++ programmer. Smile I have the following
code:

class B { public: B() {} };
class D1 : public B { public: D1() {} };
class D2 : public B { public: D2() {} };
...
class Dn : public B { public: Dn() {} };

class U
{
private:
static D1* m_D1;
static D2* m_D2;
...
static Dn* m_Dn;
public:
static B* get_D1() { return m_D1; }
static B* get_D2() { return m_D2; }
...
static B* get_Dn() { return m_Dn; }
U() { m_D1 = new D1; m_D2 = new D2; ... m_Dn = new Dn; }
~U() { delete m_D1; delete m_D2; ... delete m_Dn; }
};

The obvious problem is that I have potentially many derived classes
D1..Dn for which I don't want to have to duplicate code (class
declarations, instantiations, etc.). I have 2 questions.... Can I use
some form of compile-time template programming to:

(1) Generate classes D1..Dn?
(2) Declare static variables m_D1..m_Dn, static methods
get_D1()..get_Dn(), and construction and destruction of variables and
m_D1..m_Dn inside U() and ~U()?

I would greatly appreciate any help from the gurus out there!

Thanks very much in advance,
Whitney Kew
Software Engineer
Rain Bird Corporation
http://www.rainbird.com

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Hyman Rosen
Guest





PostPosted: Sat Apr 17, 2004 6:22 am    Post subject: Re: Compile-time programming beginner - How to do simple cla Reply with quote



Whitney Kew wrote:
Quote:
class B { public: B() {} };
class D1 : public B { public: D1() {} };
class D2 : public B { public: D2() {} };
...
class Dn : public B { public: Dn() {} };

class U
{
private:
static D1* m_D1;
static D2* m_D2;
...
static Dn* m_Dn;
public:
static B* get_D1() { return m_D1; }
static B* get_D2() { return m_D2; }
...
static B* get_Dn() { return m_Dn; }
U() { m_D1 = new D1; m_D2 = new D2; ... m_Dn = new Dn; }
~U() { delete m_D1; delete m_D2; ... delete m_Dn; }
};

template <unsigned N> struct D : public B { D() { };
template <unsigned N> struct DU
{
DU() : m_D(new D<N>) { }
~DU() { delete m_D; }
static B *get_D() { return m_D; }
private:
static D<N> *m_D;
};

class U : D<1>, D<2>, ..., D<n>
{
template <unsigned N>
static B *get_D() { return D<N>::get_D(); }
};

You can make the U inheritance fancier by coming up with a
scheme to inherit from a range, but this should get you started.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Ben Hutchings
Guest





PostPosted: Sat Apr 17, 2004 10:25 pm    Post subject: Re: Compile-time programming beginner - How to do simple cla Reply with quote



Whitney Kew wrote:
Quote:
Hello everyone,

I have a situation that seems to scream "compile-time programming" to
me, but I'm still a compile-time programming beginner, and I just
can't see the elegant solution. Having read Alexandrescu's "Modern
C++ Design," I feel like there is in fact an elegant solution! If
someone could give me some help with this, I feel like I could finally
get my feet wet in the weird world of compile-time programming, and
thus grow significantly as a C++ programmer. Smile I have the following
code:

class B { public: B() {} };
class D1 : public B { public: D1() {} };
class D2 : public B { public: D2() {} };
...
class Dn : public B { public: Dn() {} };

class U
{
private:
static D1* m_D1;
static D2* m_D2;
...
static Dn* m_Dn;
public:
static B* get_D1() { return m_D1; }
static B* get_D2() { return m_D2; }
...
static B* get_Dn() { return m_Dn; }
U() { m_D1 = new D1; m_D2 = new D2; ... m_Dn = new Dn; }

This leaks if any new-expression other than the first throws. Why are
the static variables only initialised when an instance of U is
constructed, anyway?

Quote:
~U() { delete m_D1; delete m_D2; ... delete m_Dn; }
};

The obvious problem is that I have potentially many derived classes
D1..Dn for which I don't want to have to duplicate code (class
declarations, instantiations, etc.). I have 2 questions.... Can I use
some form of compile-time template programming to:

(1) Generate classes D1..Dn?

Not with those names, but with the number as a template argument:

template<unsigned int M>
class D : public B
{
// statically assert that 1 <= M <= N
typedef char dummy[(M >= 1 && M <= N) ? 1 : -1];
};

Quote:
(2) Declare static variables m_D1..m_Dn, static methods
get_D1()..get_Dn(), and construction and destruction of variables and
m_D1..m_Dn inside U() and ~U()?

I would greatly appreciate any help from the gurus out there!

I'm not a guru, but I think I can cope with this. I don't think it
makes sense to initialise static member variables in the constructor,
so here I have given them static initialisation. This could be
changed.

class U
{
private:
template
static DHolder<N> dummy;

public:
template<unsigned int M>
static D<M> * get()
{
return DHolder<M>::m_D.get();
}
};

template<unsigned int M>
struct U::DHolder : public DHolder<M-1>
{
static std::auto_ptr<D m_D;
};
template<>
struct U::DHolder<0>
{};

template<unsigned int M>
std::auto_ptr<D U::DHolder<M>::m_D(new D<M>);

U::DHolder<N> U::dummy;

The definition of U::dummy causes implicit instantiation of
U::DHolder<N>, which through inheritance causes implicit instantiation
of U::DHolder<N-1...0>. This ensures that all the D<M>s are created
even if they aren't retrieved with U::get().

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Carl Barron
Guest





PostPosted: Sun Apr 18, 2004 12:45 am    Post subject: Re: Compile-time programming beginner - How to do simple cla Reply with quote

In article <1082129342.798000 (AT) master (DOT) nyc.kbcfp.com>, Hyman Rosen
<hyrosen (AT) mail (DOT) com> wrote:

Quote:
Whitney Kew wrote:
class B { public: B() {} };
class D1 : public B { public: D1() {} };
class D2 : public B { public: D2() {} };
...
class Dn : public B { public: Dn() {} };

class U
{
private:
static D1* m_D1;
static D2* m_D2;
...
static Dn* m_Dn;
public:
static B* get_D1() { return m_D1; }
static B* get_D2() { return m_D2; }
...
static B* get_Dn() { return m_Dn; }
U() { m_D1 = new D1; m_D2 = new D2; ... m_Dn = new Dn; }
~U() { delete m_D1; delete m_D2; ... delete m_Dn; }
};

template <unsigned N> struct D : public B { D() { };
template <unsigned N> struct DU
{
DU() : m_D(new D<N>) { }
~DU() { delete m_D; }
static B *get_D() { return m_D; }
private:
static D<N> *m_D;
};

class U : D<1>, D<2>, ..., D<n
{
template static B *get_D() { return D };

You can make the U inheritance fancier by coming up with a
scheme to inherit from a range, but this should get you started.

all most The following gets by some compiler syntax problems above

but still could create memory leaks....

first I'd add an emply class to terminate the recursion below.
template <> struct D<0> {};

template <unsigned int N>
struct DU:public DU<N-1>
{
DU() {m_D(new D<N>){}
~DU() {delete m_D;}
B *get_D() {return m_D;}
private:
D<N> *m_D;
// prevent copying or rewrite with a smart ptr....
D(const D &);
D & operator = (const D &);
};

template <class N>
class U:public DU<N>
{
template <class M>
B *get_D()
{
DU<M> *p = this;
return p->get_D();
}
};

N >=1, 1 <=M <= N in these templates...

Note the data is not static here as otherwise there will be serious
memory leaks with the solution using static data or allowing
copy/assignment.

I'd wonder what problem requires a multitude of essentiallly identical
classes.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Whitney Kew
Guest





PostPosted: Sun Apr 18, 2004 2:54 pm    Post subject: Re: Compile-time programming beginner - How to do simple cla Reply with quote

Hyman & Ben, thanks so much for responding; my comments are inline....

Ben Hutchings wrote in message ...
Quote:
Whitney Kew wrote:
Hello everyone,


[snip]

Quote:
class B { public: B() {} };
class D1 : public B { public: D1() {} };
class D2 : public B { public: D2() {} };
...
class Dn : public B { public: Dn() {} };

class U
{
private:
static D1* m_D1;
static D2* m_D2;
...
static Dn* m_Dn;
public:
static B* get_D1() { return m_D1; }
static B* get_D2() { return m_D2; }
...
static B* get_Dn() { return m_Dn; }
U() { m_D1 = new D1; m_D2 = new D2; ... m_Dn = new Dn; }

This leaks if any new-expression other than the first throws. Why are
the static variables only initialised when an instance of U is
constructed, anyway?

This has to do with the fact that I'll be trying to shoehorn this code
into a managed C++ project that I'm writing, but I don't think this is
germane to the discussion....

Quote:

~U() { delete m_D1; delete m_D2; ... delete m_Dn; }
};

The obvious problem is that I have potentially many derived classes
D1..Dn for which I don't want to have to duplicate code (class
declarations, instantiations, etc.). I have 2 questions.... Can I use
some form of compile-time template programming to:

(1) Generate classes D1..Dn?

Not with those names, but with the number as a template argument:

template<unsigned int M
class D : public B
{
// statically assert that 1 <= M <= N
typedef char dummy[(M >= 1 && M <= N) ? 1 : -1];
};


Oh dear.... I should have chosen better derived class names for my
example! The derived class names won't relate to each other via an
integral "subscript", as I originally wrote in my example. They'll be
more "random", such as:

class B { public: B() {} };
class red : public B { public: red() {} };
class blue : public B { public: blue() {} };
...
class green : public B { public: green() {} };

Quote:
(2) Declare static variables m_D1..m_Dn, static methods
get_D1()..get_Dn(), and construction and destruction of variables and
m_D1..m_Dn inside U() and ~U()?


[snip]

Quote:
I'm not a guru, but I think I can cope with this. I don't think it
makes sense to initialise static member variables in the constructor,
so here I have given them static initialisation. This could be
changed.

class U
{
private:
template
static DHolder<N> dummy;

public:
template<unsigned int M
static D {
return DHolder<M>::m_D.get();
}
};

template<unsigned int M
struct U::DHolder : public DHolder {
static std::auto_ptr m_D;
};
template
struct U::DHolder<0
{};

template std::auto_ptr U::DHolder<M>::m_D(new D<M>);

U::DHolder<N> U::dummy;

The definition of U::dummy causes implicit instantiation of
U::DHolder<N>, which through inheritance causes implicit instantiation
of U::DHolder<N-1...0>. This ensures that all the D<M>s are created
even if they aren't retrieved with U::get().

Ben, I like your suggestions, and I think this is the road down which
I want to go. But I want to go even farther, using a library such as
Alexandrescu's Loki library
([url]http://sourceforge.net/projects/loki-lib/)[/url]. An idea I have is to
generate a "type list" from the derived class names and have code
automatically generated from those types. In place of your "M - 1"
recursion mechanism, I would remove a derived type from my type list
one by one, until I reached a "null type." Using Loki code, my next
attempt is the following:

#include <memory> // std::auto_ptr<>
#include "HierarchyGenerators.h" // Loki header file

class B { public: B() {} };

template<typename D, typename Base = B>
class DHandler : public Base { /* ... */ };

class red {};
class blue {};
class green {};
typedef TYPELIST_3(red, blue, green) DTypeList;

typedef Loki::GenLinearHierarchy<DTypeList, DHandler> DHier;

class U
{
private:
// COMPILER ERROR ON LINE BELOW...
template<typename D> struct DHolder :
public DHolder<typename Loki::TL::Erase
{ static std::auto_ptr<DHandler m_D; };

template<> struct DHolder<Loki::NullType> {};

static DHolder<DTypeList> dummy;

public:
template<typename D> static DHandler<D>* get()
{ return DHolder<D>::m_D.get(); }
};

U::DHolder<DTypeList> U::dummy;

template<typename D>
std::auto_ptr<DHandler U::DHolder<D>::m_D(
new DHolder<DHier>);

But now my compiler (.NET 2003) gives me the following error:

'U::DHolder<D>' : a class cannot be its own base class
with
[
D=DTypeList
]

I feel like I'm SO close to figuring this out - do you or does anyone
else have more thoughts / suggestions? Thanks very much in advance!!

Whitney Kew
Software Engineer
Rain Bird Corporation
http://www.rainbird.com

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Carl Barron
Guest





PostPosted: Mon Apr 19, 2004 5:52 am    Post subject: Re: Compile-time programming beginner - How to do simple cla Reply with quote

In article <a384cdde.0404180127.56b21218 (AT) posting (DOT) google.com>, Whitney
Kew <wkew_rainbird1 (AT) yahoo (DOT) com> wrote:

Quote:
Hyman & Ben, thanks so much for responding; my comments are inline....

Ben Hutchings wrote in message ...
Whitney Kew wrote:
Hello everyone,


[snip]

class B { public: B() {} };
class D1 : public B { public: D1() {} };
class D2 : public B { public: D2() {} };
...
class Dn : public B { public: Dn() {} };

class U
{
private:
static D1* m_D1;
static D2* m_D2;
...
static Dn* m_Dn;
public:
static B* get_D1() { return m_D1; }
static B* get_D2() { return m_D2; }
...
static B* get_Dn() { return m_Dn; }
U() { m_D1 = new D1; m_D2 = new D2; ... m_Dn = new Dn; }

{snip]
If I read this right, a scatter hierarchy is really what you want and

access ot the proper handler is easier as well.

scatter hierarchy:
B1 B2 B3
| /
generated_class

as opposed to
B1
Quote:

B2

B3

generated_class


using Loki::GenScatterHierarchy and Loki::SmartPtr to hold the pointers
,fewer surprises with a referenced counted ptr over auto_ptr,
boost::shared ptr can be used as welll. Also made sure that the class
is polymorphic by providing a virtual destructor The code that passes
thru Codewarrrior's syntax check follows:
// begining of code
#include "SmartPtr.h"
#include "HierarchyGenerators.h"

struct Base
{
virtual ~Base();
};

template <typename T>
struct DHolder
{
static Loki::SmartPtr<T> s_D;
static Loki::SmartPtr<Base> get() {return s_D;}
static void init() {s_D = Loki::SmartPtr<T>(new T);}
};

template <class TList> struct Initialize;

template <class H,class T>
struct Initialize<Loki::Typelist
{
static void init()
{
DHolder<H>::init();
Initialize<T>::init();
}
};

template <> struct Initialize<Loki::NullType>
{
static void init(){}
};

template <class TList>
class U
{
typedef typename Loki::GenScatterHierarchy
<
TList,
DHolder
Quote:
Handlers;
static Loki::SmartPtr

public:
template <typename T>
static Loki::SmartPtr<Base> get()
{
return s_handlers::DHolder<T>::get();
};
U()
{
Initialize<TList>::init();
}
};

// specific code

class red:public Base{};
class blue:public Base{};
class green:public Base{};

typedef TYPELIST_3(red,blue,green) DTypeList;

typedef U<DTypeList> My_U;

My_U u; // delete this from your header [1]
// end of code

[1] was used only to get complete template iinstancing and hence
fairlly complete syntax checking. It should not be in a header.

Is this what you really want???

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
kanze@gabi-soft.fr
Guest





PostPosted: Tue Apr 20, 2004 10:24 am    Post subject: Re: Compile-time programming beginner - How to do simple cla Reply with quote

Ben Hutchings <do-not-spam-benh (AT) bwsint (DOT) com> wrote


Quote:
Whitney Kew wrote:

I have a situation that seems to scream "compile-time programming"
to me, but I'm still a compile-time programming beginner, and I just
can't see the elegant solution. Having read Alexandrescu's "Modern
C++ Design," I feel like there is in fact an elegant solution! If
someone could give me some help with this, I feel like I could
finally get my feet wet in the weird world of compile-time
programming, and thus grow significantly as a C++ programmer. Smile I
have the following code:

class B { public: B() {} };
class D1 : public B { public: D1() {} };
class D2 : public B { public: D2() {} };
...
class Dn : public B { public: Dn() {} };

class U
{
private:
static D1* m_D1;
static D2* m_D2;
...
static Dn* m_Dn;
public:
static B* get_D1() { return m_D1; }
static B* get_D2() { return m_D2; }
...
static B* get_Dn() { return m_Dn; }
U() { m_D1 = new D1; m_D2 = new D2; ... m_Dn = new Dn; }

This leaks if any new-expression other than the first throws. Why are
the static variables only initialised when an instance of U is
constructed, anyway?

Probably for the same reason they are deleted in the destructor. Things
should really get interesting the first time he has more than one
instance of USmile.

I didn't respond to begin with, because I couldn't figure out what his
real problem is. If the problem is just to maintain a certain (unknown)
number of static pointers to objects, something like:

struct U
{
template< typename T >
static T* get()
{
static T* const theOneAndOnly = new T ;
return theOneAndOnly ;
}
} ;

would seem to do the trick; if he absolutely needs for the destructors
to be called, then there are fairly straightforward solutions using a
smart pointer here instead of a raw pointer.

But of course, there's nothing that I would really call "compile-time
programming" in that.

--
James Kanze GABI Software mailto:kanze (AT) gabi-soft (DOT) fr
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.