I write plugins for an application through its C ++ SDK. The mechanism is quite simple. The plugin provides its functions through predefined interfaces. This is achieved due to the fact that server classes are inherited from one implementation class per interface, which contains either pure life functions or impure functions with a default implementation.
This is very practical, as SDK clients should only redefine the methods that the plugin requires and / or provide an implementation for (rare) ones without default.
What bothers me is that everything is known at compile time. Virtual function tables and mechanisms associated with run-time polymorphism are provided here only to provide default implementations.
I am trying to remove this overhead while maintaining convenience.
As an example (very contrived), let's say I have a couple of servers representing a single interface (called Blah), consisting of only one method without a default implementation.
// SDK header struct OldImpl_Blah { virtual ~OldImpl_Blah() =default; virtual int mult(int) =0; }; // plugin source class OldServer3 : public OldImpl_Blah { public: int mult(int i) override { return 3 * i; } }; class OldServer5 : public OldImpl_Blah { public: int mult(int i) override { return 5 * i; } };
For pure virtual functions, straightforward CRTP works just fine.
// SDK header template <typename T> struct NewImpl_Blah { int mult(int i) { return static_cast<T*>(this)->mult(i); } }; // plugin source class NewServer3 : public NewImpl_Blah<NewServer3> { public: int mult(int i) { return 3 * i; } }; class NewServer5 : public NewImpl_Blah<NewServer5> { public: int mult(int i) { return 5 * i; } };
The problem is unclean virtual functions, i.e. when the default implementation is used for the method.
// SDK header struct OldImpl_Blah { virtual ~OldImpl_Blah() =default; virtual int mult(int i) { return i; } // default }; // plugin source class OldServer3 : public OldImpl_Blah { public: int mult(int i) override { return 3 * i; } }; class OldServer5 : public OldImpl_Blah { public: int mult(int i) override { return 5 * i; } };
I tried combining CRTP with some SFINAE expression trick and could not.
I assume that I need some code dispatching where the base class will either provide a default implementation, or forward its implementation arguments to the derived class if one exists.
The problem is that the submission must be based on information that is not yet available to the compiler in the base class.
A simple solution would be to simply remove the virtual
and override
keywords in the code. But then the compiler will not check the conformity of function signatures.
Is there any well-known scheme for this situation? Is that what I ask for at all?
(Please use a few words, as my experience with templates is a bit on the side of the world. Thank you.)