简体   繁体   中英

How do I specify a member variable whose class is templated (composition)

The class HandleMessages below has a member variable of type ProtocolDecoder*. This was fine when ProtocolDecoder was not a template class. Now I have changed to be so, but now code won't compile.

At runtime there is a factory function which creates the required decoder.

If I can't have a member m_Decoder then how can I achieve the same effect?

If I try to declare the member as ProtocolDecoder* m_Decoder;

I get compiler error: error C2059: syntax error : '<'

and see reference to class template instantiation 'LogPlayer' being compiled

template <typename T>
class ProtocolDecoder 
{
public:
  virtual const char* ProtocolName() = 0;
  virtual ProtoWrapper<T>* DecodeMsg(const unsigned char* msg, int length) = 0;
 ...
};

class ABCDecoder : public ProtocolDecoder<ABC_msg>
{
public:
  virtual const char* ProtocolName() {return "ABC"; }

  virtual ProtoWrapper<ABC_msg>* DecodeMsg(const unsigned char* msg, int length);
};

//lots of different decoders derived from ProtocolHandler

class HandleMessages 
{
public:
void Process() {}

private:
//ProtocolDecoder<T>*      m_Decoder;  //Want a Protocol member variable - but don't know type until runtime
};

You can't use a template object without specifying the template parameters, template types only exist when all parameters have values.

So while ProtocolDecoder<int>* is a real type, ProtocolDecoder<T>* is not. What you probably want here is to make an abstract base class that all the template classes derive from. Then you can simply upcast them to the base type and store them that way.

So for example,

class BaseProtocolDecoder 
{
public:
  virtual const char* ProtocolName() = 0;
  virtual BaseProtoWrapper* DecodeMsg(const unsigned char* msg, int length) = 0;
 ...
};

template <typename T>
class ProtocolDecoder : BaseProtocolDecoder
{
public:
  const char* ProtocolName();
  BaseProtoWrapper* DecodeMsg(const unsigned char* msg, int length);
 ...
};

template<>
ProtocolDecoder<ABC_msg>
{
public:
  const char* ProtocolName() {return "ABC"; }

  BaseProtoWrapper* DecodeMsg(const unsigned char* msg, int length);
};

You will need to do the same thing for ProtoWrapper<T> , for the same reason

NOTE: Often you will want to ditch templates and simply use inheritence, because templates end up not being strictly necessary. It depends on the situation, of course, but it's always good to look over templated code occasionally and think "could I rip out the templates?"

Without seeing the full template of ProtocolDecoder I can't sure for sure whether this will work for your application, but I would pull the interface into its own class. Then your HandleMessages() class just has a pointer/reference to the interface and doesn't care about the template.

Program to an interface, not an implementation: What does it mean to "program to an interface"?

class BaseWrapper
{
};

template <class T>
class ProtoWrapper: public BaseWrapper
{
};

class BaseDecoder
{
  virtual const char* ProtocolName() = 0;
  virtual BaseWrapper* DecodeMsg(const unsigned char* msg, int length) = 0;
};

template <typename T>
class ProtocolDecoder: public BaseDecoder
{
public:
 ... // template specific code
};

class ABCDecoder : public ProtocolDecoder<ABC_msg>
{
public:
  virtual const char* ProtocolName() {return "ABC"; }

  virtual ProtoWrapper<ABC_msg>* DecodeMsg(const unsigned char* msg, int length);
};

class HandleMessages 
{
public:
void Process() {}

private:
BaseDecoder*      m_Decoder;  //Want a Protocol member variable - but don't know type until runtime
};

补充说明一下:我认为应该在这里做出决定的主要问题是模板是在编译时确定的,而您需要多态性或类似特性才能在运行时做出类似的选择。

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