不同参数计数的结构方法列表

Fabric methods list for different arguments count

本文关键字:结构 方法 列表 参数      更新时间:2023-10-16

我有一个这样的工厂,它通过传递的模板类名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> );
}

这很难,原因有两个:

  • 使用错误的参数调用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;
}