Preprocessor magic to expand template instantiation ?

Discussion in 'C++' started by mathieu, Aug 6, 2009.

  1. mathieu

    mathieu Guest

    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;
    }
     
    mathieu, Aug 6, 2009
    #1
    1. Advertising

  2. mathieu

    Ian Collins Guest

    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
     
    Ian Collins, Aug 6, 2009
    #2
    1. Advertising

  3. mathieu

    mathieu Guest

    On Aug 6, 11:45 am, Ian Collins <> 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
     
    mathieu, Aug 6, 2009
    #3
  4. mathieu <> writes:

    > On Aug 6, 11:45 am, Ian Collins <> 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__
     
    Pascal J. Bourguignon, Aug 6, 2009
    #4
  5. * Pascal J. Bourguignon:
    > mathieu <> writes:
    >
    >> On Aug 6, 11:45 am, Ian Collins <> 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
     
    Alf P. Steinbach, Aug 6, 2009
    #5
  6. "Alf P. Steinbach" <> writes:

    > * Pascal J. Bourguignon:
    >> mathieu <> writes:
    >>
    >>> On Aug 6, 11:45 am, Ian Collins <> 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__
     
    Pascal J. Bourguignon, Aug 6, 2009
    #6
  7. * Pascal J. Bourguignon:
    > "Alf P. Steinbach" <> writes:
    >
    >> * Pascal J. Bourguignon:
    >>> mathieu <> writes:
    >>>
    >>>> On Aug 6, 11:45 am, Ian Collins <> 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
     
    Alf P. Steinbach, Aug 6, 2009
    #7
  8. 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?
     
    Juha Nieminen, Aug 6, 2009
    #8
  9. * 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
     
    Alf P. Steinbach, Aug 6, 2009
    #9
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Preprocessor magic needed

    , Mar 17, 2006, in forum: C Programming
    Replies:
    8
    Views:
    353
    CBFalconer
    Mar 20, 2006
  2. Replies:
    1
    Views:
    616
    Salt_Peter
    Dec 25, 2006
  3. mathieu
    Replies:
    1
    Views:
    542
    mathieu
    Aug 6, 2009
  4. Artūras Šlajus

    Magic method instantiation

    Artūras Šlajus, Nov 5, 2006, in forum: Ruby
    Replies:
    1
    Views:
    105
    Daniel Sheppard
    Nov 5, 2006
  5. Giles Bowkett
    Replies:
    9
    Views:
    429
    Giles Bowkett
    Dec 17, 2007
Loading...

Share This Page