简体   繁体   中英

Function template parameter deduction

I am writing the small C++ message-based communication framework with using of the Reactor pattern. The problem which I have met is the serialization of the application (user-defined) messages. To prevent API from redudant information I make an assumption about the serialization function. There is an Archive class which holds the serialized form of the message, however it is the template, so the user could choose the binary form of its. The assumption is that for each message there will be only one serialization function available (defined), so the type deduction of the binary type could be cleary deduced from the function signature. Let's see the code:

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

Compiler claims that it cannot deduce the P type. Is there any other way (without traits) to help compiler with such deduction?

Kind Regard, Gracjan

EDIT(14-05-2013 15:42): According to the request in comment I attach the Traits solution:

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

In the above code, serialize is the name of a template, and used in place of a function it represents the complete set of overloads result from all possible specializations of the template (ie every possible substitution of the template arguments). At the same time archive is a template that can potentially take any function from the subset that comply with the minimal restriction that the second argument is an instantiation of the Archive template.

The problem here is not that the template cannot deduce the argument, but that there are infinite types that match the requirements, your problem is too open ended. Which brings the next question, does everything need to be a template?

In general it is a bad idea to specialize function templates, could the serialize template be really an overload? Can you reduce the generality of the problem to a situation where deducible or not there is just one or two candidates? I have the feeling that you are opening yourself to too many degrees of liberty that you might or not need and then getting bit by the fact that anything can match.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM