2

我正在使用 Reactor 模式编写基于 C++ 消息的小型通信框架。我遇到的问题是应用程序(用户定义)消息的序列化。为了防止 API 获取冗余信息,我对序列化函数做了一个假设。有一个存档类保存消息的序列化形式,但它是模板,因此用户可以选择其二进制形式。假设对于每条消息,只有一个可用的序列化函数(已定义),因此可以从函数签名中清楚地推断出二进制类型的类型推导。让我们看看代码:

template <typename T> struct Archive {
  T t;
};  // struct Archive

template <typename Message, typename T>
void serialize(const Message& msg, Archive<T>* const ar);

struct Signal {
  void* payload;
};

template <typename T> struct Wrapper {
  Signal* pack() {
    Signal* s = new Signal;
    archive(&serialize, &s->payload);
    return s;
  }

  template <typename P>
  void archive(void(*f)(const T&, Archive<P>* const), void** payload) {
    Archive<P> ar;
    f(t, &ar);
    P* p = new P;
    *p = ar.t;
    *payload = p;
  }

  T t;
};

struct TestMsg {
  int i;
};

template <>
void serialize(const TestMsg& msg, Archive<int>* const ar) {
  ar->t = msg.i;
}

int main() {
  Wrapper<TestMsg> msg;
  msg.pack();
  return 0;
}

编译器声称它无法推断出 P 类型。有没有其他方法(没有特征)来帮助编译器进行这种推断?

亲切的问候,Gracjan

编辑(14-05-2013 15:42):根据评论中的要求,我附上了 Traits 解决方案:

/****** Library part *******/
template <typename T> struct Archive {
  T t;
};  // struct Archive

template <typename T> struct MessageTrait {};

template <typename Message, typename T>
void serialize(const Message& msg, Archive<T>* const ar);

struct Signal {
  void* payload;
};

template <typename T> struct Wrapper {
  Signal* pack() {
    typedef Archive<typename MessageTrait<T>::ArchType> ArchiveType;
    Signal* s = new Signal;
    ArchiveType ar;
    serialize(t, &ar);
    return s;
  }

  T t;
};

/****** Application part ******/
struct TestMsg {
  int i;
};

template<> struct MessageTrait<TestMsg> {
  typedef int ArchType;
};

template <>
void serialize(const TestMsg& msg, Archive<int>* const ar) {
  ar->t = msg.i;
}

int main() {
  Wrapper<TestMsg> msg;
  msg.pack();
  return 0;
}
4

1 回答 1

1
template <typename Message, typename T>
void serialize(const Message& msg, Archive<T>* const ar);

template <typenane T>
Signal* Wrapper<T>::pack() {
    Signal* s = new Signal;
    archive(&serialize, &s->payload);
    return s;
}

在上面的代码中,serialize是一个模板的名字,用来代替一个函数,它代表了模板所有可能的特殊化(即模板参数的每一个可能的替换)所产生的完整的重载集。同时archive是一个模板,它可以潜在地从子集中获取任何符合最小限制的函数,即第二个参数是Archive模板的实例化。

这里的问题不是模板不能推导出参数,而是有无限类型符合要求,你的问题太开放了。这带来了下一个问题,一切都需要模板吗?

一般来说,专门化函数模板是个坏主意,serialize模板真的会过载吗?您能否将问题的普遍性简化为只有一两个候选者的情况?我有一种感觉,你正在向你可能需要或不需要的太多自由度敞开心扉,然后被任何东西都可以匹配的事实所困扰。

于 2013-05-14T13:43:37.607 回答