Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   C++ (http://www.velocityreviews.com/forums/f39-c.html)
-   -   Preprocessor magic to expand template instantiation ? (http://www.velocityreviews.com/forums/t693853-preprocessor-magic-to-expand-template-instantiation.html)

mathieu 08-06-2009 09:37 AM

Preprocessor magic to expand template instantiation ?
 
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;
}

Ian Collins 08-06-2009 09:45 AM

Re: Preprocessor magic to expand template instantiation ?
 
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;
}

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

--
Ian Collins

mathieu 08-06-2009 09:49 AM

Re: Preprocessor magic to expand template instantiation ?
 
On Aug 6, 11:45*am, Ian Collins <ian-n...@hotmail.com> wrote:
> 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.

Thanks

Pascal J. Bourguignon 08-06-2009 11:17 AM

Re: Preprocessor magic to expand template instantiation ?
 
mathieu <mathieu.malaterre@gmail.com> writes:

> On Aug 6, 11:45*am, Ian Collins <ian-n...@hotmail.com> wrote:
>> 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.

--
__Pascal Bourguignon__

Alf P. Steinbach 08-06-2009 12:00 PM

Re: Preprocessor magic to expand template instantiation ?
 
* Pascal J. Bourguignon:
> mathieu <mathieu.malaterre@gmail.com> writes:
>
>> On Aug 6, 11:45 am, Ian Collins <ian-n...@hotmail.com> wrote:
>>> 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.


Cheers & hth.,

- Alf

Pascal J. Bourguignon 08-06-2009 01:07 PM

Re: Preprocessor magic to expand template instantiation ?
 
"Alf P. Steinbach" <alfps@start.no> writes:

> * Pascal J. Bourguignon:
>> mathieu <mathieu.malaterre@gmail.com> writes:
>>
>>> On Aug 6, 11:45 am, Ian Collins <ian-n...@hotmail.com> wrote:
>>>> 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.

--
__Pascal Bourguignon__

Alf P. Steinbach 08-06-2009 03:32 PM

Re: Preprocessor magic to expand template instantiation ?
 
* Pascal J. Bourguignon:
> "Alf P. Steinbach" <alfps@start.no> writes:
>
>> * Pascal J. Bourguignon:
>>> mathieu <mathieu.malaterre@gmail.com> writes:
>>>
>>>> On Aug 6, 11:45 am, Ian Collins <ian-n...@hotmail.com> wrote:
>>>>> 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

Juha Nieminen 08-06-2009 09:11 PM

Re: Preprocessor magic to expand template instantiation ?
 
Alf P. Steinbach wrote:
> 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?

Alf P. Steinbach 08-06-2009 10:13 PM

Re: Preprocessor magic to expand template instantiation ?
 
* Juha Nieminen:
> Alf P. Steinbach wrote:
>> 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?


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


All times are GMT. The time now is 01:08 PM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.