Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Generating typelists at compile-time

3 views
Skip to first unread message

Jamie Redmond

unread,
Oct 12, 2007, 4:22:49 PM10/12/07
to
Hi,

(sorry for the double post - google groups decided to post an
unfinished message).

{Moderator's note: the incomplete message was rejected. -mod/dk}

I have a problem that seems like it should be solvable using template
metaprogramming and typelists, but I can't see a clear solution. I
have what boils down to an object factory that maps a type identifier
(class name as string) to a pointer to a creation function. At run-
time, I load objects saved to disk by reading in the name of the type
to create and then invoking the creation function if it was found in
the map (otherwise an error is triggered because of the unknown
class).

This has been working well but in order for an entry to appear in the
map a static function needs to be called for each class at run-time
(e.g. MyNewType::Register()). I would like to be able to change that
to a single statement that does not need to be updated each time a new
class is added to the system. So what I'd like to do is automatically
create the typelist at compile-time and then iterate that list adding
the appropriate mapping entires. It seems that all of the information
needed to do this is available at compile time.

I'm new to typelists and template metaprogramming in general and I'm
not sure how to go about doing this. Is something like this even
possible? Is it possible to generate a typelist like this at compile
time?

Thanks,
- Jamie


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

MathGis

unread,
Oct 14, 2007, 12:25:00 AM10/14/07
to
On Oct 12, 10:22 pm, Jamie Redmond <jamie.redm...@gmail.com> wrote:

> a static function needs to be called for each class at run-time
> (e.g. MyNewType::Register()). I would like to be able to change that
> to a single statement that does not need to be updated each time a new
> class is added to the system. So what I'd like to do is automatically
> create the typelist at compile-time and then iterate that list adding
> the appropriate mapping entires.


This is what I ended up with:


#include <boost/mpl/for_each.hpp>

template <class T> struct typewrap {};

struct ClassReg {
template <class T>
void operator ()(typewrap<T>) const
{
T::Register();
}
};

void RegAll()
{
boost::mpl::for_each<YourTypeListHere, typewrap<_> >(ClassReg());
};


Still any shorter solutions available? Let us know?

Maarten

int...@gmail.com

unread,
Oct 14, 2007, 12:40:16 AM10/14/07
to
On Oct 13, 12:22 am, Jamie Redmond <jamie.redm...@gmail.com> wrote:
> I have a problem that seems like it should be solvable using template
> metaprogramming and typelists, but I can't see a clear solution. I
> have what boils down to an object factory that maps a type identifier
> (class name as string) to a pointer to a creation function. At run-
> time, I load objects saved to disk by reading in the name of the type
> to create and then invoking the creation function if it was found in
> the map (otherwise an error is triggered because of the unknown
> class).
>
> This has been working well but in order for an entry to appear in the
> map a static function needs to be called for each class at run-time
> (e.g. MyNewType::Register()). I would like to be able to change that
> to a single statement that does not need to be updated each time a new
> class is added to the system.

It is not entirely clear what you want to achieve: a single (but
separate) statement per each class you want to be aware of, and then
some way to enumerate all classes described by such statements? Or a
single statement for all classes, somewhere (but that would obviously
have to list the classes explicitly)?

Jamie Redmond

unread,
Oct 14, 2007, 8:49:20 AM10/14/07
to
On Oct 14, 6:40 am, int...@gmail.com wrote:

> It is not entirely clear what you want to achieve: a single (but
> separate) statement per each class you want to be aware of, and then
> some way to enumerate all classes described by such statements? Or a
> single statement for all classes, somewhere (but that would obviously
> have to list the classes explicitly)?

Yes to the first one. I would like a way to flag each class (at its
definition) and then enumerate all of those appending them to a
typelist. That's phase 1 of the problem. Phase 2 is then going
through that typelist and generating the "Register()" calls, which I
think boost::mpl::for_each or some other variant can do provided that
I already have a typelist containing all of the types that I wish to
register (which requires me to enumerate the MyNewTypes and add them
to a typelist 'by hand' - which itself is error prone if a new
programmer adds a new MyNewClass type and forgets to go update the
typelist).

So now the problem is just phase 1, and I'm not sure that there is a
good solution to that. I thought of having a 'global typelist
typedef' MyNewClasses and deriving each MyNewClass from a registration
template that would append MyNewClass to the MyNewClasses typelist,
but that would involve somehow redefining the MyNewClasses typedef
which isn't legal C++. Also any solution would have to be immune to
compilation order issues; e.g. the site where the typelist is iterated
and the Register() calls are generated would have to be compiled after
all of the MyNewClasses have been parsed and added to the 'global'
typelist. It's phase 1 of this problem that I'm not sure is possible,
but I'd like to get this forum's opinion on it before I completely
write it off.

- Jamie

Jamie Redmond

unread,
Oct 14, 2007, 8:49:11 AM10/14/07
to
On Oct 14, 6:25 am, MathGis <mtahilfer...@hotmail.com> wrote:

> This is what I ended up with:
>
> #include <boost/mpl/for_each.hpp>
>
> template <class T> struct typewrap {};
>
> struct ClassReg {
> template <class T>
> void operator ()(typewrap<T>) const
> {
> T::Register();
> }
>
> };
>
> void RegAll()
> {
> boost::mpl::for_each<YourTypeListHere, typewrap<_> >(ClassReg());
>
> };

This looks like it would work well after I've generated the typelist,
so that answers the second part of my question. The first part is
what I'm more concerned with solving. The first part needs to
automatically generate the typelist from a set of classes.

e.g. Instead of having to explicitly write this in the code: typdef
typelist<MyNewType1, MyNewType2, MyNewType3> MyNewTypes, I would like
to be able to automatically generate MyNewTypes; maybe by deriving
from some registration template like this:

class MyNewType1 : public Registration<MyNewType1> {};

Is there a way to automatically generate a typelist at compile time
without having to explicitly type out each class name in the
typelist's definition? It is tedious and error prone to have to check-
out and edit a separate file and add each new class to a typelist
definition. It would be much cleaner and less error prone to have the
compiler automatically do that by including some "magic" at the site
of the class definition.

- Jamie

Jeffrey Schwab

unread,
Oct 14, 2007, 12:29:38 PM10/14/07
to
On Oct 12, 1:22 pm, Jamie Redmond <jamie.redm...@gmail.com> wrote:

> I have a problem that seems like it should be solvable using template
> metaprogramming and typelists, but I can't see a clear solution. I
> have what boils down to an object factory that maps a type identifier
> (class name as string) to a pointer to a creation function. At run-
> time, I load objects saved to disk by reading in the name of the type
> to create and then invoking the creation function if it was found in
> the map (otherwise an error is triggered because of the unknown
> class).
>
> This has been working well but in order for an entry to appear in the
> map a static function needs to be called for each class at run-time
> (e.g. MyNewType::Register()). I would like to be able to change that
> to a single statement that does not need to be updated each time a new
> class is added to the system. So what I'd like to do is automatically
> create the typelist at compile-time and then iterate that list adding
> the appropriate mapping entires. It seems that all of the information
> needed to do this is available at compile time.
>
> I'm new to typelists and template metaprogramming in general and I'm
> not sure how to go about doing this. Is something like this even
> possible? Is it possible to generate a typelist like this at compile
> time?
>
> Thanks,
> - Jamie

It seems like the set of classes is not guaranteed to be final at
compile-time; i.e., you could always (in principle) load a shared
object/dynamically-linked library with a static object whose
constructor registered a new type with the factory. If the factory
really does know about all of the types at compilation, you're
probably already stuck maintaining a list of them, in the form of a
sequence of header inclusions.

jtorj...@yahoo.com

unread,
Oct 14, 2007, 7:40:52 PM10/14/07
to
> I'm new to typelists and template metaprogramming in general and I'm
> not sure how to go about doing this. Is something like this even
> possible? Is it possible to generate a typelist like this at compile
> time?
>

Not 100% sure what you want to achieve, and why you think you need
typelists.

An easy way to do what you want is to have the class you're
registering derive from a templated do_register class, which has a
static variable - when the static variable is initialized, it
registers your type. Something like this:

template<class type> struct do_register_impl {
do_register_impl() {
// do the registration
}
};

template<class type> struct do_register {
do_register() {
// do a trick that will force the compiler to create
// the auto_register instance
}
private:
static do_register_impl<type> auto_register;
};

Your class will only need to derive from do_register<>, and
registration happens automatically:

class my_type : ..., do_register<my_type> { ... };


I've implemented something similar in win32gui -- every window class
automatically registers itself.

Best,
John


--
http://John.Torjo.com -- C++ expert
... call me only if you want things done right

Jamie Redmond

unread,
Oct 15, 2007, 3:56:57 PM10/15/07
to
On Oct 15, 1:40 am, jtorjo2...@yahoo.com wrote:

> template<class type> struct do_register {
> do_register() {
> // do a trick that will force the compiler to create
> // the auto_register instance
> }
> private:
> static do_register_impl<type> auto_register;
>
> };

What is the trick to force the compiler to create the auto_register
instance without having to instantiate a my_type object?

- Jamie

Jeffrey Schwab

unread,
Oct 22, 2007, 9:15:39 PM10/22/07
to
On Oct 14, 4:40 pm, jtorjo2...@yahoo.com wrote:
> > I'm new to typelists and template metaprogramming in general and I'm
> > not sure how to go about doing this. Is something like this even
> > possible? Is it possible to generate a typelist like this at compile
> > time?
>
> Not 100% sure what you want to achieve, and why you think you need
> typelists.

My understanding is that Jamie would like a static list of types, so
that his program can do some per-type processing at compile-time. The
reasons are probably efficiency and type-safety.

> An easy way to do what you want is to have the class you're
> registering derive from a templated do_register class, which has a
> static variable - when the static variable is initialized, it
> registers your type.

That does allow client code to replace an explicit call to a
registration function with an implicit invocation of a base class
constructor, but the work is still done at run-time. Jamie's feeling
-- and I'm not sure I disagree with him -- was that the information
would be available at compile-time, so why wait?

Jeffrey Schwab

unread,
Oct 22, 2007, 9:18:35 PM10/22/07
to
On Oct 15, 12:56 pm, Jamie Redmond <jamie.redm...@gmail.com> wrote:
> On Oct 15, 1:40 am, jtorjo2...@yahoo.com wrote:
>
> > template<class type> struct do_register {
> > do_register() {
> > // do a trick that will force the compiler to create
> > // the auto_register instance
> > }
> > private:
> > static do_register_impl<type> auto_register;
>
> > };
>
> What is the trick to force the compiler to create the auto_register
> instance without having to instantiate a my_type object?

The auto_register instance is a static variable, so it gets created
automatically at the beginning of the program. The trick is that you
now have a separate base class type, each with its own auto_register
instance, for each derived (plugin) type. This is because the base
class template (do_register) is parameterized with the derived class
type, so do_register<FirstPlugin> and do_register<SecondPlugin> are
distinct types. There are then separate, static instances,
do_register<FirstPlugin>::auto_register and
do_register<SecondPlugin>::auto_register. Be forewarned that the
compiler may try desperately to elide the static registration
(auto_register) objects, if they are never accessed, even though they
have side effects. In the code below, compiled with g++ 4.1, the
second plugin type never gets registered.

// g++ -ansi -pedantic -Wall -O0 main.cc -o main

#include <iostream>
#include <iterator>
#include <list>
#include <string>

namespace {
typedef std::string name_type;
typedef std::list<name_type> name_list_type;

name_list_type plugin_names;
}

template<typename PluginT>
struct plugin_base_t {

private:
static struct registration_t {
registration_t() {
plugin_names.push_back(PluginT::name());
};
} registration_;

public:
static registration_t* registration() { return &registration_; }
};

template<typename PluginT>
typename plugin_base_t<PluginT>::registration_t
plugin_base_t<PluginT>::registration_;

/* plugin classes; instantiations of do_register cause construction
* of do_register_impl_ objects on program startup.
*/
struct first_plugin_t: plugin_base_t<first_plugin_t> {
static name_type name() { return "first_plugin"; }
};

struct second_plugin_t: plugin_base_t<second_plugin_t> {
static name_type name() { return "second_plugin"; }
};

int main() {

/* Force instantiation of registration object for first_plugin_t.
*/
(void) plugin_base_t<first_plugin_t>::registration();

std::copy(
plugin_names.begin(), plugin_names.end(),
std::ostream_iterator<name_type>(std::cout, "\n"));

return 0;

0 new messages