C++: "specializing" a member function template to work for derived classes from a certain base class

StackOverflow https://stackoverflow.com/questions/21509542

Question

I have a base class MessageBase, from which I derive various other message classes, e.g., MessageDerived. I have another class that does some processing on various types of data, including a catchall method template:

struct Process {
  void f(int a);
  void f(const char* b);
  template<typename T> void f(const T &t) { ... }
};

So if I call Process::f on a message object, the template method is called.

Now I want to add custom functionality for for my message classes. I am not allowed to change Process, so I want to derive from it (but even if I could change it, I can't find a way to get the custom functionality). I tried:

struct ProcessDerived : public Process {
  void f(const MesaageBase& m) { ... }  // Custom functionality for messages.
};

But that only works when I call ProcessDerived::f on a MessageBase object. If I invoke it on a MessageDerived object, the template method gets selected instead.

Is there a way to get the custom function selected on all message classes while letting the template catch all other types?

Était-ce utile?

La solution

You need to use SFINAE here. Here is an example (note that it needs c++11 to work):

struct ProcessDerived : public Process
{
  template<typename T> void f(const T &t, typename std::conditional<std::is_base_of<MessageBase, T>::value, int, void>::type = 0)
  {
    /// do something specific
  }

  template<typename T> void f(const T &t, ...)
  {
    return Process::f (t);
  }
};

};

You can read more about it at http://en.wikipedia.org/wiki/Substitution_failure_is_not_an_error

Autres conseils

ProcessDerived::f shadows all definitions of Process::f (see here: Overloading rules for inheritance in C++). So calling ProcessDerived::f with a MessageDerived object calls ProcessDerived::f(const MessageBase&) as this is the only visible f, but e.g.

ProcessDerived pd; 
pd(42);

won't compile. You need to add a

using Process::f;

in ProcessDerived for the problem you described showing up. The solution proposed by Alex Telishev while I was writing fixes both problems at once, however.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top