Preprocessor magic to expand template instantiation ?

M

mathieu

Hi there,

I am looking for a trick to avoid maintaining the 'Create' function
as describe below. All it does is a simple template instantiation, are
there any trick which would avoid having to maintain this 'Create' as
the number of enum grows ?

Thanks

typedef enum {
TYPE1,
TYPE2
} TYPES;

class type {};
class type1 : public type {};
class type2 : public type {};

template <int T> struct Factory;
template <> struct Factory<TYPE1> { typedef type1 Type; };
template <> struct Factory<TYPE2> { typedef type2 Type; };

type* Create(TYPES e)
{
switch(e)
{
case TYPE1:
return new Factory<TYPE1>::Type;
break;
case TYPE2:
return new Factory<TYPE2>::Type;
break;
}
}

int main()
{
type *t1 = Create(TYPE1);
type *t2 = Create(TYPE2);
return 0;
}
 
I

Ian Collins

mathieu said:
Hi there,

I am looking for a trick to avoid maintaining the 'Create' function
as describe below. All it does is a simple template instantiation, are
there any trick which would avoid having to maintain this 'Create' as
the number of enum grows ?

Thanks

typedef enum {
TYPE1,
TYPE2
} TYPES;

class type {};
class type1 : public type {};
class type2 : public type {};

template <int T> struct Factory;
template <> struct Factory<TYPE1> { typedef type1 Type; };
template <> struct Factory<TYPE2> { typedef type2 Type; };

type* Create(TYPES e)
{
switch(e)
{
case TYPE1:
return new Factory<TYPE1>::Type;
break;
case TYPE2:
return new Factory<TYPE2>::Type;
break;
}
}

What about

template <int N>
type* create()
{
return Factory<N>::type;
}

int main()
{
type *t1 = create<TYPE1>();
type *t2 = create<TYPE2>();
return 0;
}
 
M

mathieu

What about

template <int N>
type* create()
{
   return Factory<N>::type;

}

Ooops, I missed the whole point of my issue. 'TYPE' are read from a
file, so I need a dynamic binding which is not expressed in my
example. I'll try to post another example.

Thanks
 
P

Pascal J. Bourguignon

mathieu said:
Ooops, I missed the whole point of my issue. 'TYPE' are read from a
file, so I need a dynamic binding which is not expressed in my
example. I'll try to post another example.

Depends. Is this file determined when you compile the program, or is
it determined at run time?

In the former case, you can generate the function to instanciate the
templates with a mere sed command:

instanciate.c++ : types.h
( echo 'void instanciateTemplate(){' ;\
sed -n -e '/typedef enum/,/} TYPES/s/^ *\([A-Z][A-Za-z0-9]*\),?/{type * t=create<\1>();}/p <types.h \;
echo '}' ) > instanciate.c++

In the later case, you will have to generate at run time such a
function, then fork the compiler to compile it in a dynamically
loadable library, load it dynamically and call it.
 
A

Alf P. Steinbach

* Pascal J. Bourguignon:
mathieu said:
Ooops, I missed the whole point of my issue. 'TYPE' are read from a
file, so I need a dynamic binding which is not expressed in my
example. I'll try to post another example.

Depends. Is this file determined when you compile the program, or is
it determined at run time?

In the former case, you can generate the function to instanciate the
templates with a mere sed command:

instanciate.c++ : types.h
( echo 'void instanciateTemplate(){' ;\
sed -n -e '/typedef enum/,/} TYPES/s/^ *\([A-Z][A-Za-z0-9]*\),?/{type * t=create<\1>();}/p <types.h \;
echo '}' ) > instanciate.c++

In the later case, you will have to generate at run time such a
function, then fork the compiler to compile it in a dynamically
loadable library, load it dynamically and call it.

Have you ever heard of overkill?

Besides, shared libraries are not supported by standard C++, which is the topic
in this group.

I fail to understand why the OP, and now you, cannot see the trivial solution,
which is to use a map of functions, or just a simple array. It's on a par with
using a variable where you need a variable. And actually it is exactly that,
using a variable where you need one, that's the level of the question.


Cheers & hth.,

- Alf
 
P

Pascal J. Bourguignon

Alf P. Steinbach said:
* Pascal J. Bourguignon:
mathieu said:
mathieu wrote:
Hi there,
I am looking for a trick to avoid maintaining the 'Create' function
as describe below. All it does is a simple template instantiation, are
there any trick which would avoid having to maintain this 'Create' as
the number of enum grows ?
Thanks
typedef enum {
TYPE1,
TYPE2
} TYPES;
class type {};
class type1 : public type {};
class type2 : public type {};
template <int T> struct Factory;
template <> struct Factory<TYPE1> { typedef type1 Type; };
template <> struct Factory<TYPE2> { typedef type2 Type; };
type* Create(TYPES e)
{
switch(e)
{
case TYPE1:
return new Factory<TYPE1>::Type;
break;
case TYPE2:
return new Factory<TYPE2>::Type;
break;
}
}
What about

template <int N>
type* create()
{
return Factory<N>::type;

}
Ooops, I missed the whole point of my issue. 'TYPE' are read from a
file, so I need a dynamic binding which is not expressed in my
example. I'll try to post another example.

Depends. Is this file determined when you compile the program, or is
it determined at run time?

In the former case, you can generate the function to instanciate the
templates with a mere sed command:

instanciate.c++ : types.h
( echo 'void instanciateTemplate(){' ;\
sed -n -e '/typedef enum/,/} TYPES/s/^ *\([A-Z][A-Za-z0-9]*\),?/{type * t=create<\1>();}/p <types.h \;
echo '}' ) > instanciate.c++

In the later case, you will have to generate at run time such a
function, then fork the compiler to compile it in a dynamically
loadable library, load it dynamically and call it.

Have you ever heard of overkill?

Besides, shared libraries are not supported by standard C++, which is
the topic in this group.

I fail to understand why the OP, and now you, cannot see the trivial
solution, which is to use a map of functions, or just a simple
array. It's on a par with using a variable where you need a
variable. And actually it is exactly that, using a variable where you
need one, that's the level of the question.

The OP says that the list of TYPEs is read from a file.

We may assume that he means from a source file, known at compilation
time, and hence the first part of my answer, where you may generate
the code you propose automatically from the file containing the list
of types. (When this list doesn't change often, ie. I tend to actually
generate the code from a chunk of emacs lisp in a comment directly in
the sources).

But we may assume wrong (since he mentionned the term 'dynamic'), and
if he really meant at run-time, then we'd need something more
sophisticated, involving run-time use of a compiler.


Now the question that I ask, is that given that we can assume you're a
programmer, how come you don't understand an answer in the form of a
simple 'if'?

Don't you understand that it is more efficient communication wise,
when there is an ambiguity in the question, to return the two answers,
with, when it's possible, the discriminating condition?

If it was a chat, instead of a usenet article, of course we could
first ask the question and then give only the right answer, but even
in this case, it could be worthwhile to expose the two answers and the
condition, since the question intended to clarify the OP question
might not be well understood itself... Hopefully, the exposing of the
alternative answer should let the OP help discriminate better his
problem.
 
A

Alf P. Steinbach

* Pascal J. Bourguignon:
Alf P. Steinbach said:
* Pascal J. Bourguignon:
mathieu wrote:
Hi there,
I am looking for a trick to avoid maintaining the 'Create' function
as describe below. All it does is a simple template instantiation, are
there any trick which would avoid having to maintain this 'Create' as
the number of enum grows ?
Thanks
typedef enum {
TYPE1,
TYPE2
} TYPES;
class type {};
class type1 : public type {};
class type2 : public type {};
template <int T> struct Factory;
template <> struct Factory<TYPE1> { typedef type1 Type; };
template <> struct Factory<TYPE2> { typedef type2 Type; };
type* Create(TYPES e)
{
switch(e)
{
case TYPE1:
return new Factory<TYPE1>::Type;
break;
case TYPE2:
return new Factory<TYPE2>::Type;
break;
}
}
What about

template <int N>
type* create()
{
return Factory<N>::type;

}
Ooops, I missed the whole point of my issue. 'TYPE' are read from a
file, so I need a dynamic binding which is not expressed in my
example. I'll try to post another example.
Depends. Is this file determined when you compile the program, or is
it determined at run time?

In the former case, you can generate the function to instanciate the
templates with a mere sed command:

instanciate.c++ : types.h
( echo 'void instanciateTemplate(){' ;\
sed -n -e '/typedef enum/,/} TYPES/s/^ *\([A-Z][A-Za-z0-9]*\),?/{type * t=create<\1>();}/p <types.h \;
echo '}' ) > instanciate.c++

In the later case, you will have to generate at run time such a
function, then fork the compiler to compile it in a dynamically
loadable library, load it dynamically and call it.
Have you ever heard of overkill?

Besides, shared libraries are not supported by standard C++, which is
the topic in this group.

I fail to understand why the OP, and now you, cannot see the trivial
solution, which is to use a map of functions, or just a simple
array. It's on a par with using a variable where you need a
variable. And actually it is exactly that, using a variable where you
need one, that's the level of the question.

The OP says that the list of TYPEs is read from a file.

We may assume that he means from a source file, known at compilation
time, and hence the first part of my answer, where you may generate
the code you propose automatically from the file containing the list
of types. (When this list doesn't change often, ie. I tend to actually
generate the code from a chunk of emacs lisp in a comment directly in
the sources).

No, code generation isn't necessary in this case. A simple template will do.

But we may assume wrong (since he mentionned the term 'dynamic'), and
if he really meant at run-time, then we'd need something more
sophisticated, involving run-time use of a compiler.

No, it's not necessary to involve run-time use of a compiler in this case.

Now the question that I ask, is that given that we can assume you're a
programmer, how come you don't understand an answer in the form of a
simple 'if'?

I understood it. It's complete overkill. ;-)


Don't you understand that it is more efficient communication wise,
when there is an ambiguity in the question, to return the two answers,
with, when it's possible, the discriminating condition?

Yep, that's good idea.

If it was a chat, instead of a usenet article, of course we could
first ask the question and then give only the right answer, but even
in this case, it could be worthwhile to expose the two answers and the
condition, since the question intended to clarify the OP question
might not be well understood itself... Hopefully, the exposing of the
alternative answer should let the OP help discriminate better his
problem.

The best discrimination in this case would be to disregard both possible answers.


Cheers & hth.,

- Alf
 
J

Juha Nieminen

Alf said:
I fail to understand why the OP, and now you, cannot see the trivial
solution, which is to use a map of functions, or just a simple array.
It's on a par with using a variable where you need a variable. And
actually it is exactly that, using a variable where you need one, that's
the level of the question.

How do you populate the map without basically replicating his Create()
function?
 
A

Alf P. Steinbach

* Juha Nieminen:
How do you populate the map without basically replicating his Create()
function?

There are a number of possibilites.

If the type numbers are consecutive then a recursive template can do it.

If the type numbers are more arbitrary then with each specialization of the
Factory<N> type include registration in the map.

If the map isn't used before entry of 'main', then each of the OP's Factory<N>
types can be self-registrating, like this (eror handing omited):


<code>
#include <map>

struct Type { virtual ~Type() {} };
struct Type1: Type {};
struct Type2: Type {};

typedef Type* (*FactoryFunc)();
typedef std::map<int, FactoryFunc> FactoryFuncs;

FactoryFuncs& factoryFuncs()
{
static FactoryFuncs theFuncs;
return theFuncs;
}

template< int N, class T >
struct RegisterFactoryFunc
{
static Type* create() { return new T(); }

static bool registerFactory()
{
factoryFuncs()[N] = &create;
return true;
}

static bool const theRegistrar;
};

template< int N, class T >
bool const RegisterFactoryFunc<N, T>::theRegistrar =
RegisterFactoryFunc<N, T>::registerFactory();


enum TypeNumber
{
typeNumber1,
typeNumber2
};

template struct RegisterFactoryFunc< typeNumber1, Type1 >;
template struct RegisterFactoryFunc< typeNumber2, Type2 >;


Type* create( TypeNumber n )
{
return factoryFuncs()[n]();
}

#include <iostream>
#include <typeinfo>
int main()
{
using namespace std;
Type* const p1 = create( typeNumber1 );
Type* const p2 = create( typeNumber2 );

cout << typeid(*p1).name() << endl;
cout << typeid(*p2).name() << endl;
}
</code>


Cheers & hth.,

- Alf
 

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

No members online now.

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top