I have a rather complex set of C++ object dependencies and I’m using templates to manage object specialization. I find templates confusing but they avoid a lot of problems with object casting that I really like. I now find myself needing to convert a class into a template simply so that I can pass the passed template type to a subclass – the class receiving the template specialization doesn’t care about the template type because it operates on the type’s base class. This class has a lot of logic that I don’t want to specialize and I’m trying to find a way to avoid that.
Here’s a simplified example. Call this file “cars.h”:
#include <iostream>
using std::cout, std::endl;
class baseEngine { public: void start() { cout << "vroom" << endl; }};
class GasEngine : public baseEngine {};
class DieselEngine : public baseEngine {};
// Needs "T"
template <class T>
class baseVehicle {
public: T engine;
};
// Only needs "T" to pass to the baseVehicle
template <class T>
class Body : public baseVehicle<T> {
public:
void drive(); // I don't want to duplicate all of these foreach engine T.
void park(); // Some of these use the baseEngine interface but not all.
void honk(); // None of them need to use the specialized "T" variant.
void brake(); // What are my options? Can I ::forward<> something?
virtual void fillup() = 0; // Derived classes need to provide this.
};
// These use the specialized template "T" values.
class GasCar : public Body<GasEngine> { public: void fillup() {}};
class DieselCar : public Body<DieselEngine> {};
// HydrogenEngine, NuclearEngine, HampsterEngine, etc.
// Other stuff that makes this tricky
class baseBadge {};
class BlueOval : public baseBadge {};
class baseFord : public BlueOval {};
// The thing I actually need to deal with
class FordFreestyle : public baseFord, public GasCar {};
class FordRollsCoal : public baseFord, public DieselCar {};
And here is “cars.cpp”:
#include "cars.h"
// There's no need to make many copies of this.
template<class T>
void Body<T>::drive() { this->engine.start(); }
// Conceptually, this should work logically but it gives linker errors.
template<>
void Body<baseEngine>::drive() { this->engine.start(); }
// This is the working non-template code, but "template <>" undefines this as its own class
void Body::drive() { this->engine.start(); }
// void Body::honk() { /* nothing to do with the engine */ }
// void Body::brake() { /* nothing to do with the engine */ }
int main()
{
FordFreestyle myCar;
myCar.drive();
myCar.fillup();
// GasCar gCar;
// DieselCar dCar;
// dCar.drive();
// dCar.fillup();
return 0;
}
This doesn’t seem like that unusual a construction but what is the answer? I realize I can put all this logic into the header file but that seems like a huge waste, and I really don’t care for that as an idiom. But is that just how it is? Does the compiler or linker drop all the functions that don’t depend on <T>
or are these dozens of specialized functions getting called just because that’s how the templates defined them?