3

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)

Georg Fritzsche
  • 97,545
  • 26
  • 194
  • 236
smerlin
  • 6,446
  • 3
  • 35
  • 58
  • Smells like you need to implement a factory and `clone` methods. Using a `clone()` interface, you can create objects of a family and not need to know their class name. – Thomas Matthews Jan 16 '10 at 01:04
  • I don't want to seem critical, but really... this smells bad. First of all the use of `typeid` is quite controversial, but I would also like to point out the inefficiency of such a method > you perform a search with linear complexity and you have to actually precise ALL the possible types that could get generated... and I don't even want to think about the nightmarish maintenance cost. – Matthieu M. Jan 16 '10 at 16:47
  • typeid can be easily substituted with a static ::name function, linear search is not an issure since i only call this method once (besides that any other object factory ive looked at also has a linear search or abuses macros) – smerlin Jan 16 '10 at 19:03

4 Answers4

3

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
  • 55,802
  • 15
  • 111
  • 149
2

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

Community
  • 1
  • 1
Dmitry
  • 6,590
  • 2
  • 26
  • 19
1

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
  • 18,794
  • 5
  • 57
  • 67
  • Already tried that, still got `error: no matching function for call to 'get_classobject(const char*&)'|` – smerlin Jan 15 '10 at 23:07
0

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

Community
  • 1
  • 1
epatel
  • 45,805
  • 17
  • 110
  • 144
  • when using that pattern you have to write the code yourself, using my way the compiler generates it for me ;) – smerlin Jan 15 '10 at 23:33
  • @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 Jan 16 '10 at 00:25
  • 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 Jan 16 '10 at 07:58