0

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
};
Angus Comber
  • 9,316
  • 14
  • 59
  • 107

4 Answers4

1

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?"

Dan
  • 12,409
  • 3
  • 50
  • 87
0

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"?

Community
  • 1
  • 1
Ryan Guthrie
  • 688
  • 3
  • 11
0
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
};
queen3
  • 15,333
  • 8
  • 64
  • 119
0

To add a little to other things that have been said: I think the main issue that should be making your decision here is that templates are decided at compile-time, while you need polymorphism or similar to make choices like that at run-time.

Orion
  • 35
  • 4