简体   繁体   中英

How to make Derived class templated on Base class in CRTP

Lets say, I have two Engine classes (based on fuel type eg Gas or Electric)

template<class Derived>
class ElectricEngine {};

and

template <typename Derived>
class GasEngine {};

Now say I want to make CarEngine and PlaneEngine , each of which can choose one of the above base classes. Also I need to do CRTP (static polymorphism). So a straight forward way to do this are as following:

class ElectricCarEngine : public ElectricEngine<ElectricCarEngine> {};
class GasCarEngine : public GasEngine<GasCarEngine> {};

class ElectricPlaneEngine : public ElectricEngine<ElectricPlaneEngine> {};
class GasPlaneEngine : public GasEngine<GasPlaneEngine> {};

The above works, but its lot of redundant code, since my methods of each CarEngine types ie ElectricCarEngine and GasCarEngine are same. Its the same story for ElectricPlaneEngine and GasPlaneEngine .

Assuming something like below compiles :

template <typename Base>
class CarEngineInterface : public Base<CarEngineInterface<Base> > {};

We can then reuse this class to create any CarEngine Types by simple typedfs. For example:

typedef CarEngineInterface<ElectricCarEngine> ElectricCarEngine;
typedef CarEngineInterface<GasCarEngine> ElectricCarEngine;

However this fails because of the cyclic dependency. How can I achieve a similar effect?

Is there some traits magic to solve this? (Like the ones used to refer Derived class typedefs from base classes in CRTP)

I am on C++99 but I can use Boost. Also I am a noob in c++ templates.

Let me know if I need to clarify anything.

Ideaone link: https://ideone.com/uMylVY

Templates can also accept templates as arguments, so I think this will serve:

template< class Engine > struct ElectricFueled { };
template< class Engine > struct GasFueled { };

template< template<class> class Fueled > struct CarEngine   : Fueled<CarEngine<Fueled> >   { };
template< template<class> class Fueled > struct PlaneEngine : Fueled<PlaneEngine<Fueled> > { };

CarEngine<ElectricFueled> myTeslaEngine;
PlaneEngine<GasFueled>    myMooneyEngine;

This might be the simplest way to break it out in terms of structural syntax, but it's only one way to do it. Try lots of variations to see what's going to make life easiest later on.

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM