C++ Template Method Polymorphism

Polymorphism in C++ means a function or object of the same identity/name behaves differently under different scenarios. A common example of polymorphism is a derived class could override the method definition in the base class if it is marked virtual and a base class pointer would invoke the proper definition according to which class instance it is actually pointing to.

Polymorphism reduces trivial programming efforts in some cases and is very useful. Template method for generic programming is another style of polymorphism done at compile time to avoid unnecessary code duplication and eases the burden of programmers (see my earlier post series). However, C++ forbids template methods to be marked as virtual. So could somehow we have it all?

The need to have virtual template method hits me recently in such a scenario: When designing a header-only framework, the developer wishs to do generic programming, so that the framework could be compiled along with the core compute functions which are from application programmers and might contains arbitrary data types at programmers’ choice; Mainwhile, it is ideal to keep the framework flexible and extensible so the framework developers could explore different runtime designs that would augment the behavior of some common methods.

On my first thought, I would just try some code like the follows:

However, it turns out to be a compiler error and I learned C++ does not allow template method to be virtual. Learned from several articles online, here I figured out one solution for my need.

Basically this approach uses a class to wrap the data and have a virtual function with the wrapper data type as the argument and/or return type for delegation. To enable the virtual function to recover the data type properly, the datatype is captured as a template parmeter of the derived class. Here comes the code test this design:

The another issue occurs that with the underlying data structure uses the data type chosen by the application programmers, surely the application programmers could invoke the template methods with the proper template parameter. However, if the runtime wants to perform some operations with the data structure, there seems no way to call the template method. Template parameter is determined at compiling time not during execution. When the base class pointer is the only thing that runtime has, although the data type is captured by the derived class template parameter list, and should have been saved somewhere, it cannot be retrived.

I ended up creating another functor class to kind play the trick again, that creates typeless interfaces for runtime to use.

With this functor approach, here is how we can design the framework:

And here comes an example showing how to write applications on top of the framework.

This framework design gives both the application programmers and the runtime developers freedom to explore on their own parts and their code could arbitrarily combined and compile together.

There are many other workarounds to achieve samilar goals. For example, replacing virtual methods with templates, which seems to have performance benefits as well (because some runtime efforts to find the right method now happen at template instantiation during compiling). Nevertheless, I need to save pointers to different derived class in one place (e.g., a STL container), so I cannot just have different template arguments. There are also mentions on boost::any and std::any, which I feel is probably similar to the approach I took. More advanced, multi-method is said to be another solution.

Credits