函数注册与动态组合(1)

我们这里讨论这么一个问题:

给定一族 C++ 函数,如何动态的调用它们?

我们希望通过某个其他的语言来描述这些函数的 dependency,但是同时使用 C++ 本身作为一个 main entry。这个问题的选择会有非常多,比如之前讨论过的 lua,又或者通过别的 declarative 语言描述的关系。假定我们已经有一族写好的函数,那么我们需要一个工具将他们映射到另一个语言的 domain,同时在操纵这些“对象”时,我们需要完成具体的函数调用过程,并将结果传递给下一个函数。

我们假想的一个 API 如下

REGISTER_FUNCTION(do_something);

这个 macro 很显然可以拿到 do_something 这个函数的 signature,我们可以用 boost::function_traits 运算获得需要的参数类型以及返回值类型。我们需要把这个函数与某个类型关联起来,这样我们才能在另一个环境下通过这个类型完成需要的一些行为(将几个函数串联起来)。同时如果将这部分 export 到其他的语言里面,就可以用其他的语言来实现这些功能了。很显然这个类型需要处理从 strong type 的世界(其 method 的实现)到一个 type erasure 的世界(操纵这些对象)互相的转变。很显然我们必须把函数连接的关系通过 erasure 之后的类型进行操作。

注册机制

一个简单的注册机制应该包括几个东西:

  • static 的容器,用来存放 string 到每个类型的关系,比如使用 std::map 之类的东西
  • initializer 对象,用来创建每条 std::map 的记录,它本身也是 static 对象

这样一来我们很明显存在 static object 初始化顺序问题。这个注册机制提供给我们 factory method,这样我们可以将它 export 到其他语言用来生成组成 call graph 的边。一个典型的注册 API 包括

DEFINE_FACTORY(MyInterface);
REGISTER_SUBCLASS(MyInterface, FooImpl);

当然如果 factory method 的参数可以有多个,这里的 DEFINE_REGISTERER 会复杂许多。对与实现而言,很显然我们需要为 MyInterface 生成一个单独的 registerer,因此

template <typename IFace, typename... Args>
struct factory {
  using container = std::map<std::string, std::function<IFace*(Args...)>>;
  container ctors;

  const std::function<IFace*(Args...)>& ctor(const std::string& name) {
    auto result = ctors.find(name);
    if (result != ctors.end()) {
      return result->second;
    }
    throw std::runtime_error("cannot find the constructor");
  }

  template <typename Impl>
  struct registerer {
    registerer(const std::string& name, container& c) {
      auto result = c.insert(std::make_pair(name, [](Args&&... args) {
	    return new Impl(std::forward<Args>(args)...);
	  }));
      assert(result.second);
    }
  };
};

#define DEFINE_FACTORY(IFace, ...) \
  static factory<IFace, ##__VA_ARGS__> IFace##_factory

#define REGISTER_SUBCLASS(IFace, Impl) \
  static decltype(IFace##_factory)::registerer<Impl> \
  Impl##_init(#Impl, IFace##_factory.ctors)

当然这是一个可能不是那么正确的实现。anyway 这个东西足够表示出来我们需要的东西。例如我们如果称每个 function 在这个实现里面对应一个 graph 的 node 的话,我们可以如下使用上面的宏

DEFINE_FACTORY(node);

#define REGISTER_FUNCTION(func) \
  REGISTER_SUBCLASS(node, fnode<decltype(&func), &func>)
Advertisements
函数注册与动态组合(1)

发表评论

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 更改 )

Twitter picture

You are commenting using your Twitter account. Log Out / 更改 )

Facebook photo

You are commenting using your Facebook account. Log Out / 更改 )

Google+ photo

You are commenting using your Google+ account. Log Out / 更改 )

Connecting to %s