So I've got some compile time polymorphism in some legacy code. ie
I have a base class to use that takes in a template parameter.
template<typename HANDLER>
class Base
{
virtual HANDLER * make_handler();
// other methods
};
make_handler
constructs the HANDLER using a specific constructor that takes in two arguments (important later).
The handler is generally the only thing we need to change for code sharing that does a single method std::size_t handle_data(const char *, std::size_t length);
which is the entry point
class SpecificHandler
{
SpecificHandler(uint32_t id, uint32_t source_id);
std::size_t handle_data(const char *, std::size_t length);
// other methods
};
That we use by
class Child : public Base<SpecificHandler>
{
// other overridden methods
};
The problem I have is that I would like to pass in another parameter in my SpecificHandler class ie
class OtherSpecificHandler
{
OtherSpecificHandler(uint32_t id, uint32_t source_id, uint32_t other_id);
};
unfortunately the Base class calls the two argument constructor in the template.
The work around I have at the moment is to override the make_handler()
call to return the handler created with the 3 argument constructor ie
class Child : public Base<OtherSpecificHandler>
{
virtual OtherSpecificHandler * make_handler();
// other overridden methods
};
Unfortunately because the template stuff is done at compile time I have to still provide the 2 argument constructor, (in fact I just provided a default argument for the third argument), which feels wrong.
Normally I would solve this problem using dependency injection with a pointer for the Handler rather than using templates, but this is used in a lot of places and I would rather not change it.
What are my other options?
Thanks
First thing that comes to mind is making the base class method pure virtual:
template<typename HANDLER>
class Base
{
virtual HANDLER * make_handler() = 0;
//other stuff
};
That would of course mean that every derived class has to overload make_handler
, even if every other handler class has the same two-argument constructor. To avoid the repetition in that, insert another layer into the hierarchy:
template<typename HANDLER>
class BaseWithStandardHandlerConstruction : public Base<Handler>
{
virtual HANDLER * make_handler() override //maybe final as well?
{
return new HANDLER("meow", 4);
}
//that's it - nothing else goes here...
};
Then any class with a "normal" handler derives from the latter, while classes with "special" handlers derive from the former:
class Child : public BaseWithStandardHandlerConstruction<SpecificHandler>
{
// other overridden methods, no make_handler needed
};
class OtherChild : public Base<OtherSpecificHandler>
{
virtual OtherSpecificHandler * make_handler() override;
// other overridden methods
};
You may template specialize Base
Something like
template <>
OtherSpecificHandler* Base<OtherSpecificHandler>::make_handler() {
return new OtherSpecificHandler(42, 5, 12); // With correct parameter ofc.
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.