1

Is there some common way to define a interface for template member functions? I would like to create some pure abstract base classes with declarations of template member functions that should be overridden in the derived classes. Than I want to be able to call the functions of the derived classes through the interface. I know that virtual template member functions are not allowed. So till now I came up with the following solution (see below). What I would like to know is if my approach is bad design or if there are some better ways to achieve my goal:

Edit: What I want to implement is an serialization system (similar to boost::serialization). Therefor I would like to have a common base-interface function serialize which can be used to save and load objects. The correct function calls for save and load will be determined by the provided derived archive classes when calling the *do_serialize* function.

Because I'm not sure about my provided solution I would like to ask if there are maybe better ways (or even simpler ways) to achieve my goal?

The interfaces:

template<typename Derived>
class Archive{
public:
  virtual ~Archive() = 0 {}

  template<typename T>
  Archive& serialize(T t) {
    Derived* derived = static_cast<Derived*>(this);
    return derived->serialize_derived(t);
  }
};

template<typename Derived>
class Writer : public Archive<Derived> {
public:
  virtual ~Writer() = 0 {}

  template<typename T> 
  void write(const T& t) {
    Derived* derived = static_cast<Derived*>(this);
    derived->write_derived(t);
  }
};

template<typename Derived>
class Reader : public Archive<Derived> {
public:
  virtual ~Reader() = 0 {}

  template<typename T> 
  void read(const T& t) {
    Derived* derived = static_cast<Derived*>(this);
    derived->read_derived(t);
  }
};

The derived classes:

class BinaryWriter : public Writer<BinaryWriter> {
public:
  template<typename T>
  BinaryWriter& serialize_derived(T t) {
    save(t);
    return *this;
  }

  template<typename T>
  void save(T t) {
    std::cout << "DerivedWriter::save: " << t << std::endl;
  }

  template<typename T> 
  void write_derived(const T& t) {
    std::cout << "DerivedWriter::write_derived: " << t << std::endl;
  }
};

class BinaryReader : public Reader<BinaryReader> {
public:
  template<typename T>
  BinaryReader& serialize_derived(T t) {
    load(t);
    return *this;
  }

  template<typename T>
  void load(T t) {
    std::cout << "DerivedWriter::load: " << t << std::endl;
  }

  template<typename T> 
  void read_derived(const T& t) {
    std::cout << "DerivedReader::read_derived: " << t << std::endl;
  }
};

The example test function and calls (Note: calls to the Writer/Reader-interface are required in similarly (other derived Writer/Reader-classes are here omitted (i.e. TextReader, XMLReader, etc.))):

template<typename Derived, typename T>
void do_serialize(Archive<Derived>& obj, T t) {
  obj.serialize(t);
}

DerivedWriter dw;
DerivedReader dr;

do_serialize(dw, 1);
do_serialize(dr, 2);

The output:

DerivedWriter::save: 1
DerivedReader::read: 2
mkh
  • 135
  • 1
  • 8
  • What problem are you trying to solve? – Kerrek SB Jul 26 '12 at 22:02
  • 1
    Why doesn't `test` just take a `Derived& obj` and call the correct method directly? (Since you need to know the derived type at compile time and can't really make it like a virtual function anyway.) – aschepler Jul 26 '12 at 22:04
  • What you are doing is called `CRTP` (or static polymorphism) and quite common. Where is the actual question? Templates don't need interfaces, as they are checked at compile time (Not considering `Concepts`). – pmr Jul 26 '12 at 22:11
  • Thanks for the replies. I think formulation was bad. What I basically trying to implement is a boost-similar serializer. Where the base class is used as an interface writing/reading. I will update my example to make it clearer... – mkh Jul 26 '12 at 22:23
  • @aschepler I would like to have a only one general *do_serialize* (prior *test*) function which accepts all kinds of derived classes as it's parameter. If *do_serialize* takes the derived class directly I think I would have to overload the function?! – mkh Jul 27 '12 at 10:25

1 Answers1

2

After knowing this technique is called CRTP (thanks to pmr) I found this post CRTP to avoid virtual member function overhead which I think answers my question. As stated in the answer of Kerrek SB in that post this technique can be used to provide an interface. In my case this interface can be defined even for template member functions.

It seems this pattern is quite common (which I was not sure about) so I will accept it as the answer to my question.

Thanks for all your replies!

Community
  • 1
  • 1
mkh
  • 135
  • 1
  • 8