Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overriding a templated function with a polymorphic one

If I have

template<class T>
TalkyBuffer& operator<<(T const &object) { // Template
...
}
TalkyBuffer& operator<<(TalkySerialisable const &object); // Override

and a class

class A : public TalkySerialisable {
...}

Then if I perform

TalkyBuffer b;
A test;
b << test;

Then gcc is calling the Template function rather than the Override function

However if I specifically define an override

TalkyBuffer& operator<<(A const &object); // Override without polymorphism

Then gcc picks that one. Is there a practical way to override a templated function with an abstract class?

I read this but it doesn't shed light onto what happens when you throw polymorphism into the mix: http://www.gotw.ca/publications/mill17.htm Also I couldn't find a solution here but perhaps I'm using the wrong terms.

like image 793
Elliot Woods Avatar asked Nov 04 '22 12:11

Elliot Woods


2 Answers

When defining the function TalkyBuffer& operator<<(TalkySerialisable const &object); You are not overriding. You are overloading the tmeplated function.

But, when the complier sees b << test;, it searches for an operator that wants an A. It has one, it's the templated function that requires no automatic cast. This is the best choice.

The overloaded function requires an automatic cast (from A to TalkySerialisable) on the parameters to fit the declaration, and is not the best choice.

like image 104
Didier Trosset Avatar answered Nov 09 '22 14:11

Didier Trosset


I think it's possible to use a simple function based solution, reusing function overload for derivation.

struct specialized {};
struct generic {};

template <class T>
TalkyBuffer& serialize(TalkyBuffer& buffer, T const& object, generic) {
  ...
}

generic dispatch(...) {} // always picked up last in overload resolution

template <class T>
TalkyBuffer& TalkyBuffer::operator<<(T const& object) { // Template
  return serialize(*this, object, dispatch(object));
}

Now, let's implement your custom class:

TalkyBuffer& serialize(TalkyBuffer& buffer,
                       TalkySerialisable const& object,
                       specialized);

specialized dispatch(TalkySerialisable const&) {}    

And create a derived one:

class A: public TalkySerialisable {};

So, what happens ?

  • TalkyBuffer::operator<<(T const&) will be picked up
  • when trying to resolve the overload for serialize, it will first compute the result of dispatch
  • when resolving the result of dispatch, dispatch(TalkySerializable const&) is a better match than dispath(...), thus the return type is specialized
  • the generic serialize cannot be used (there is no conversion from specialized to generic), so inheritance kicks in
like image 28
Matthieu M. Avatar answered Nov 09 '22 15:11

Matthieu M.