0

我有一个这样的工厂,它通过传递的模板类名 T 实例化对象:

template<class T>
class Factory0
{
public:
    static void *Create(){ return new T(); }
};

template<class T, class Argument1>
class Factory1
{
public:
    static void *Create( Argument1 &arg1 ){ return new T( arg1 ); } 
};

我需要做这样的事情:

map<string[ClassName], &factory] _builder;
...
template<class T>
Add(){
    if( T derived from BaseClass ) _builder[T] = &factory1::Create
    else if( T derived from BaseClass ) _builder[T] = &factory0::Create;
}
template<class T>
Create() {
    return _builder[T]( (factory0) ? <nothing> : <some_argument> );
}
4

1 回答 1

2

这很难有两个原因:

  • 使用错误参数调用 create 只能在运行时被捕获,因此我们需要一些动态类型。
  • C++ 真的不喜欢转换函数指针。或者创建指向模板函数的指针。或者通常用函数指针做任何复杂的事情。

但这是可以完成的:

#include<string>
#include<map>
#include<iostream>

using namespace std;

struct returnable {
  // Put some interesting virtual functions here
};

struct foo : public returnable {
  foo() {
    cout << "defaulFoo" << endl;
  }
  foo(int x) {
    cout << "Foo:" << x << endl;
  }
};

struct bar : public returnable {
  bar(char a, char b){
    cout << "bar:" << a << "," << b << endl;
  }
};

template<typename... ARGS>
struct newmakerbase {
  virtual returnable* make(ARGS... args) = 0;
};

template<typename OUT, typename... ARGS>
struct newmaker : public newmakerbase<ARGS...> {
  virtual returnable* make(ARGS... args) {
    return new OUT(args...);
  }
};

// Boost might provide a neater version of this
int nextId = 0;
template<typename... T>
struct typeId {
  static const int id;
};
template<typename... T>
const int typeId<T...>::id = nextId++;

map<string,void*> builders;
map<string,int> argtypes;

template<typename OUT, typename... ARGS>
void registerClas(string name) {
  builders[name] = static_cast<void*>(new newmaker<OUT,ARGS...>());
  argtypes[name] = typeId<ARGS...>::id;
}

template<typename... ARGS>
returnable* create(string name, ARGS... args) {
  int argsgiven =  typeId<ARGS...>::id;
  if (argsgiven != argtypes[name]) {
    // TODO: maybe throw an exception or something?
    return NULL;
  }
  newmakerbase<ARGS...>* builder = static_cast<newmakerbase<ARGS...>*>(builders[name]);
  return builder->make(args...);
}

main() {
  registerClas<foo>("defaultFoo");
  registerClas<foo,int>("foo");
  registerClas<bar,char,char>("bar");

  returnable* a = create("defaultFoo");
  returnable* b = create("foo", 42);
  returnable* c = create("foo", 'a', 'b'); // returns NULL
  returnable* d = create("foo", 42.0); // also returns NULL
  returnable* e = create("bar", 'c', 'd');
  cout << a << " " << b << " " << c << " " << d << " " << e << endl;
}
于 2013-03-08T03:06:36.813 回答