views:

156

answers:

4

I am searching for a way to determine at runtime, which type of object should be alloced (based on a given class name, which is of type const char*).

Well the simplest way of course is to use loads of ifs /else ifs, but that doesnt seem applicable, because i have > 100 different classes(well at least they all derive from one base class), and i have to add new classes quite regularly aswell.

I already came up with a first draft, but sadly it doesnt compile yet (mingw & g++ 4.4)

template<typename TBase, typename TDerived, typename... TArgs>
Base* get_classobject(const char* classname)
{
    if(strcmp(classname,typeid(TDerived).name())==0)
        return new TDerived; //
    else if(sizeof...(TArgs)>0)
        return get_classobject<TBase,TArgs...>(classname);
    else
        return 0;
}


int main()
{
    Base* obj = get_classobject<Base,A,Foo,B,C>("Foo");
    // ^- Types A B C and Foo are all derived from Base
    delete obj; //of course we got an virtual dtor ;)
    return 0;
}

but that sizeof...(TArgs)>0 doesnt stop gcc from trying to generate code for get_classobject<TBase,const char*>(const char*) which fails

Do you have any idea, how to fix this, or any other idea ? Thanks.

EDIT: i solved it:

template<typename TBase, typename TDerived>
Base* get_classobject(const char* classname)
{
    if(strcmp(classname,typeid(TDerived).name())==0)
        return new TDerived;
    return 0;
}

template<typename TBase, typename TDerived, typename TArg, typename... TArgs>
Base* get_classobject(const char* classname)
{
    if(strcmp(classname,typeid(TDerived).name())==0)
        return new TDerived;
    return get_classobject<TBase,TArg,TArgs...>(classname);
}

EDIT For interested readers:
You should now that the implementation above is NOT compiler independent at all. The output of typeif(sometype).name() is compiler/implementation specific. Using a static const char* name variable or function inside all Derived classes, would fix this, but adds a bunch of work(of course you can use a macro for this, but if you are using macros already, you could aswell use another object factory method)

+4  A: 

Can't you just declare

template<typename TBase, typename TDerived, typename TArg, typename... TArgs>

?

Then you can specialize for the case of

typename TBase, typename TDerived, typename TArg
Kornel Kisielewicz
wouldnt it even fail one recursion step earlier if i do that ?
smerlin
You're trying to get 1+ template parameters, instead of 0+ right? You can specialize the template for the 0 case.
Kornel Kisielewicz
worked like a charm once i understood you.
smerlin
+2  A: 

Read the answers over here, you likely need a factory.

Dmitry
A: 

This sounds like you are looking for the classical object factory pattern. Have a look at this stackoverflow question. Personally I like this method

epatel
when using that pattern you have to write the code yourself, using my way the compiler generates it for me ;)
smerlin
@smerlin If I understand *your* way you will need to chain/write all derived classes every time you need to call `get_classobject()`. So when adding a class or removing one this is an administrative/manual process. The way I describe is a little more *automatic*. Basically you only need to add two lines. METADECL in the class declaration and METAIMPL in a compile-unit (.cpp file), preferably close to a constructor. This automated feature of this solution is what really appeals to me, one can then even add classes in runtime by loading shared objects (.so/.dll files) Done that...
epatel
i only have to call this function once anyway, and if i had to call them more than once, i would add an (inline) wrapper function, so that i only have to write the classes once
smerlin
+1  A: 

How about making a specialized get_classobject() with no variadic temlates? That would stop the recursion.

You would then have one definition with variadic template, and another one of just template<typename TBase, typename TDerived>. Another idea is to make a non-template overload that accepts just const char*, and returns 0.

Pavel Radzivilovsky
smerlin