功能模板参数扣除

时间:2013-05-14 03:39:08

标签: c++ templates

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

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;
}

1 个答案:

答案 0 :(得分: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模板真的可能是一个过载吗?您是否可以将问题的一般性降低到 deducible与否只有一两个候选人的情况?我觉得你正在向自己开放你可能或不需要的太多自由度,然后通过任何可以匹配的事实得到一点点。