简体   繁体   中英

C++ template specify type by Enum

I'm facing a problem : I want to create a function which calls a specific template type constructor depending on a enum that the function will receive. By that i mean :

  typedef   ____ (Class<whatever>::*tabType)(int flag);

  template<typename T>
  static Class*  Class<t>::createClassInstance(enum precision)
  {
    static const ___ createTab[] = {
    Class<int>,
    Class<double>
    }
   return (new createTab[precision](1));
  }

There are a number of ways of achieving this sort of thing, but it sounds like you want to create an array (or map) of factory methods (one for each class), indexed by the enum variable. Each one calls the relevant constructor, and returns a new object of that type.

Of course, for this to make any sense, all of the classes must derive from a common base.

If the enum value is dynamic as a function argument, you'll have to use either a dispatch table or switch/if-else. Notice that your pseudo code does not clearly explain the requirement. Say, what exactly the createInstance function you wish to define and how is it going to be called?

I would say, just construct a std::map that maps the enum to a factory function ( boost::function<> ). Then you just add one entry for each type that you want, with its corresponding enum . To actually construct the factory functions. You can either have some static Create() function for each class and store a function pointer. Or, you can use Boost.Lambda constructor/destructor functors. Or, you can use Boost.Bind to construct functors that wrap a factory function that requires some number of parameters. Here is an example:

#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/lambda/construct.hpp>
#include <map>

struct Base { };

struct Derived1 : public Base { };

struct Derived2 : public Base {
  static Base* Create() { return new Derived2; };
};

struct Derived3 : public Base {
  int value;
  Derived3(int aValue) : value(aValue) { };
  static Base* Create(int aValue) { return new Derived3(aValue); };
};

enum DerivedCreate { ClassDerived1, ClassDerived2, ClassDerived3 };

int main() {
  std::map< DerivedCreate, boost::function< Base*() > constructor_map;
  constructor_map[ClassDerived1] = boost::lambda::new_ptr<Derived1>();
  constructor_map[ClassDerived2] = &Derived2::Create;
  constructor_map[ClassDerived3] = boost::bind(&Derived3::Create, 42);

  //now you can call any constructor as so:
  Base* ptr = constructor_map[ClassDerived2]();
};

I might have made some slight syntax mistakes, but basically you should be able make the above work. Also, the fact that you have several class templates plays no role, once they are instantiated to a concrete class (like Class<int> or Class<double> ) they are just like any other class, and the above idea should remain valid.

Extending your example, something like the following works:

enum Prec {INT, DOUBLE};

struct Base
{
    virtual ~Base () = 0 {}
};

template<typename T> struct Class : public Base
{
    static Base* create (int flag) {return new Class<T> (flag);}
    Class (int flag) {}
};

typedef Base* (*Creator) (int flag);

Base* createClassInstance (Prec prec)
{
    static const Creator createTab[] = {
        Class<int>::create,
        Class<double>::create
    };

    return createTab[prec] (1);
}

int main (int argc, char* argv[])
{
    Base* c = createClassInstance (DOUBLE);

    return 0;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM