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

类型检查

很显然 STL 里面提供给我们了一些 RTTI 的接口,比如 type_info 它返回的 hash code 可以用来判断两个类型是否相同,这对于一个简单的 type check 足够了。需要注意的大约是 type_info 和 type_index 的区别,前者是 static 对象,无法 copy 或者赋值,而后者是对前者的指针,因此具有“值”的语义,这样才能放在容器里面作为 key/value。通过 typeid 返回的 type_info 对象我们可以获得需要 hash_code。

node a, b;  // initialize a, b
a.output_type(0) == b.input_type(1);  // check whether a's first output can match b's second input

这是一个超级简化的版本,我们知道 C++ 的函数传递参数的时候如果返回 int32 传递给接受 int64 的函数也是可以 work 的,因为两个类型可以 implicitly 转换;同时如果输入类型是 base class 而输出类型是一个子类的话也是可以成功的。但是使用 type_index 来判断却不是很合理。这里我们先按照这一点来实现,后面讨论是否有更为合理的 type checking 策略。

需要注意的是 typeid 获得的 type_info 是不包括 const,也不管是不是引用的。

cnode 的特化

我们很显然可以为基本类型 int/float/string 进行特化,同时我们也希望支持所有的 protobuf,类似这种问题 std::enable_if_t 是一个不错的选择。

template <typename T>
struct cnode : public node {
  void set(const T& value);
};

template <typename T, typename std::enable_if_t<std::is_base_of<proto::Message, T>::value>>
struct cnode : public node {
  void set(const T& value);
  void set(const std::string& type, const std::string& value);
};

我们甚至可以将 protobuf 的支持改成 dynamic 生成的过程。比如为了让外部可以对 cnode 进行赋值,我们提供对应的 set 方法。这样我们就可以根据 Value 中的 kind_case 来进行处理

node* setup(const Value& value) {
  auto kind = value.kind_case();
  node* result;
  switch (kind) {
    case Value::kInt32Value:
      auto* int32_value = new cnode<int32>;
      int32_value.set(value.int32_value());
      result = int32_value;
      break;
    case ...:
      // ...
    case Value::kProtoValue:
      auto* proto_value = new pnode;
      const auto& proto = value.proto_value();
      proto_value.set(proto.type(), proto.payload());
      result = proto_value;
      break;
    default:
      throw std::runtime_error("unsupported");
  }
  return result;
}

其实这也说明这样设计下我们甚至不需要 register 这些 constructor,因为我们在这里通过 oneof 可以手动生成支持的 case。

Advertisements
函数注册与动态组合(3)

发表评论

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