C++ Template Specialization with Inheritance - c++

Following Situation:
class FeatureBase
class Feature1 : public FeatureBase
class FeatureAttrBase
class Feature1Attr : public FeatureAttrbase
FeatureBase contains a list of FeatureAttrBase and should be able to create and manage these objects. Therefore i use a template on FeatureBase.
template<class T = FeatureAttrBase> class FeatureBase
creating and managing the attributes (e.g. new T())
and the subclasses use a specialized inheritance
class Feature1 : public FeatureBase<Feature1Attr>
Anywhere else in my code i wrote a method
RegisterFeature(FeatureBase<FeatureAttrBase>* feature)
but the compiler gives me an error that it was unable to convert between Feature1 and FeatureBase. In the mentioned method i only need to use information from FeatureAttrBase. But inside Feature1 i need access to Feature1Attr.
Thus the question is how to solve this issue? Do i have to change my datastructure?

Having template parameters inherit from each other doesn't make template classes related. You should instead do something like the following (might not be the best solution but you haven't specified what you are trying to do):
class FeatureAttrBase;
class FeatureBase
{
public:
virtual FeatureAttrBase* GetAttributes() = 0;
};
template<class T>
class FeatureImpl : public FeatureBase
{
T attr;
public:
FeatureAttrBase* GetAttributes()
{
return &attr;
}
};
class Feature1Attr : public FeatureAttrBase;
class Feature1 : public FeatureImpl<Feature1Attr>;
In fact, you probably don't need the FeatureImpl class and can put the implementation directly in the Feature1 class (and get rid of templates completely).

You could inherit the specialisations of FeatureBase from FeatureBase<FeatureAttrBase>. Something like this:
// Forward declaration
template <typename T>
class FeatureBase;
// Type selecting trait class FeatureBase_BaseClass
// FeatureBase for derived Attrs will inherit from FeatureBase<FeatureAttrBase>
template <typename T>
struct FeatureBase_BaseClass
{
typedef FeatureBase<FeatureAttrBase> Type;
};
// FeatureBase<FeatureAttrBase> will inherit from a dummy type
template <>
struct FeatureBase_BaseClass<FeatureAttrBase>
{
struct Type {};
};
// Use FeatureBase_BaseClass to select the proper base class for FeatureBase
template <typename T = FeatureAttrBase>
class FeatureBase : public FeatureBase_BaseClass<T>::Type
{
//as before
};
This way, all FeatureBase<X> for specific attributes X will inherit from FeatureBase<FeatureAttrBase>.

Related

Extending a CRTP template functionality

I'm a bit new to templates so bear with me if I'm asking obvious questions.
Given the following class hierarchy:
template<typename T>
class Singleton_T
{
...
static T& getInstance(){ ... }
...
}
template<typename T>
class Pool_T: public Singleton_T<Pool_T<T> >
{
...
T* createObject();
...
}
Now I want a class that extends the Pool_T functionality while also being a Singleton_T.
So I want to have in the new class the methodsgetInstance defined in Singleton_T and createObject defined in Pool_T tailored to my new type.
The initial approach would be:
struct myStruct;
class Manager : public Pool_T<myStruct>
{
...
void loadObjectsFromFile();
...
}
However , this makes the GetInstance of the Singleton_T to instantiate and return Pool_T<myStruct> type, so the loadObjectsFromFile method won't be available via getInstance (an object of Manager type won't be created).
In order to solve this I made the following change in hierarchy :
template< typename TDerrived, typename T>
class Pool_T : public Singleton_T < TDerrived >
{
...
T* createObject();
...
}
class Manager : public Pool_T<Manager, myStruct>
{
...
loadObjectsFromFile();
...
}
Now I can use all the three methods: getInstance, createObject and loadObjectsFromFile.
However this forces Pool_T to no longer be possible to instantiate from only 1 type.
EG:
struct someStruct;
class StructPool : public Pool_T<someStruct>; // no longer possible
In order to "solve" this i defined another template:
template <typename T>
class AlonePool_T: public Pool_T<AlonePool_T<T>, T>
{
// empty class
// allows instantiation of what was previously Pool_T<someStruct>
}
Now I can use this where previously Pool_T<someStruct> was defined.
struct someStruct;
class StructPool : public AlonePool_T<someStruct>;
However this will result in allot of find and replace in code that I'm not owner off.
Is there any way to achieve the following:
maintain Pool_T original definition
create a class that extends the Pool_T functionality (adds the loadObjectsFromFile method)
the class has getInstance and createObject methods correctly implemented (the correct types are used)
EDIT:
Added three methods to better underline the desired effect.
Given's liliscent's answer I changed the hierarchy to better show what I'm after.
If I understand your question correctly, a typical CRTP implementation of your hierarchy is:
template<class T>
struct Singleton {};
template<class Derived, class T>
struct Pool
: public Singleton<Derived>
{};
struct MyStruct {};
struct Manager
: public Pool<Manager, MyStruct>
{};

static_pointer_cast through inheritance and template

I am having trouble finding a fix for the following error, thrown when compiling a std::static_pointer_cast<>():
error: invalid static_cast from type ecse::EventSubscriptionManager<ecse::BaseEvent>* to type ecse::EventSubscriptionManager<TestEvent>*
I have the following hierarchy. In the end they will be filled with POD type members and will most likely become structs.
class BaseEvent {};
template <class E>
class Event : public BaseEvent, public Type<E> {};
class TestEvent : public Event<TestEvent> {};
I am currently working on the Subscribe function part of the EventManager, however when compiling I am receiving the error posted above. Note: E::ID() is defined in the class as Type and is used for identifying the class type.
template <class E>
class EventSubscriptionManager
{
public:
void Subscribe(std::function<void(E)> fptr);
private:
std::function<void(E)> event_function_;
};
class EventManager
{
public:
template <class E>
void Subscribe(std::function<void(E)> fptr)
{
std::shared_ptr<EventSubscriptionManager<E>> sub_manager_ptr;
auto sub_manager_iterator = sub_managers_.find(E::ID());
if(sub_manager_iterator == sub_managers_.end())
{
sub_manager_ptr = std::make_shared<EventSubscriptionManager<E>>();
}
else
{
sub_manager_ptr = std::static_pointer_cast<EventSubscriptionManager<E>>(sub_manager_iterator->second);
}
// Continue function...
}
private:
std::unordered_map<std::size_t, std::shared_ptr<EventSubscriptionManager<BaseEvent>>> sub_managers_;
}
I believe that the issue is that between the TestEvent and the BaseEvent there is the Event<E> class with the template, with TestEvent inheriting Event<TestEvent> instead of BaseEvent. Is this true? If so, how can I set up my hierarchy to allow for this type of casting?
If that is not the case, what is the issue with the above static cast?
I can tell you why it does not compile. This is because
EventSubscriptionManager<E>
is unrelated to
EventSubscriptionManager<BaseEvent>
So, according to point 1.) on the reference page,
static_cast<EventSubscriptionManager<E>*>((EventSubscriptionManager<BaseEvent>*)nullptr)
is ill-formed.
However, without knowing the background I can't tell what to do as a workaround.
Just: you have to relate the two classes, or choose a completely new design.
In order to do so, here is a minimal example why it fails which might be helpful:
struct Base {};
struct Derived : Base {};
template<typename T>
struct Foo {};
int main()
{
static_cast<Foo<Derived>*>((Foo<Base>*)nullptr);
}
You can try to improve on that.
In C++, there is no covariance or contravariance, there is no relationship between T<Base> and T<Sub>, even if there is one between Base and Sub.
You either need to build a common ancestor of different EventSubscriptionManager instances (e.g: EventSubscriptionManagerBase), and use that, or provide a converting constructor.

alternative to virtual typedef

I have an interface IEnumerable for template classes of List<>, Array<> and Dictionary<>. I was hoping to use typedef to get their templated types T.
I was hoping to do the following.
class IEnumerable
{
public:
virtual typedef int TemplateType;
}
And then override in inherited member, but you cant make a virtual typedef. So is there any other way that i could get the type of an unknown template class (IEnumerable is not template)?
Well, here is what is discussed in the comments in case somebody with the same question later finds this.
Basically, you want to do something similar to C#'s List<>, Array<>, IEnumerable and IEnumerator. However, you don't want to have to create a generic parent class Object because it may mean that you'll need to dynamic_cast every time.
Additionally, you don't want to make IEnumerable a template because you don't want to have to know the type when using the collection.
In fact, with C++11, you can make IEnumerable a template and not have to know the type by using the implicit type keyword auto, which is the C++11 equivalent of c#'s var keyword.
So to do this, what you can do is:
template <class T>
class IEnumerable {
public:
virtual IEnumerator<T> getEnumerator() = 0;
// and more stuff
}
then
template <class T>
class List : public IEnumerable<T> {
public:
virtual IEnumerator<T> getEnumerator() {
return ListEnumerator<T>(this);
}
}
and
template <class T>
class ListEnumerator : public IEnumerator<T> {
public:
T getNext(); // or something to this effect
// and more stuff
}
Finally, when it comes to using it, you can do:
List<int> myList;
auto i = myList.getEnumerator();
int z = i.getNext()+1;

C++ class template as property type

I have a class template in a c++ project:
template<class RequestHandler = DefaultRequestHandler>
class Server { ... }
I then have another class in which I want to hold an instance of Server<WhateverRequestHandlerIWant> as a property. So currently I have something like:
class OtherClass {
public: Server<>* server;
};
Unless I am mistaken, this will only allow me to store Server classes in which the template parameter is the class DefaultRequestHandler, correct?
Is there a way to write this without just making OtherClass a class template as well?
You could add a common abstract class for all server-like classes:
class IServer { ... };
then
template<class RequestHandler = DefaultRequestHandler>
class Server : virtual public IServer { ... }
and
class OtherClass {
public: IServer* server;
};

Factory pattern and class templates in C++

I have a hierarchy of class templates. At the top of the hierarchy is an abstract base class (interface). I won't know which concrete implementation to instantiate until runtime, so it seems like the perfect situation to use the factory pattern. However, virtual member function templates are not allowed in C++.
How can I achieve a legal design similar to the below in C++?
The individual concrete implementations of the IProduct interface as well as the concrete factories will live in different dynamic libraries, one or more of which will be loaded at runtime.
template<class T> class IProduct
{
public:
virtual void doWork(const T & data) = 0;
};
template<class T> class ProductA : public IProduct<T> {/*...*/};
template<class T> class ProductB : public IProduct<T> {/*...*/};
class IProductFactory
{
public:
template<class T> virtual IProduct<T> * createProduct() = 0;
};
class ProductAFactory: public IProductFactory
{
public:
template<class T> virtual IProduct<T> * createProduct()
{
return new ProductA<T>;
}
};
class ProductBFactory: public IProductFactory
{
public:
template<class T> virtual IProduct<T> * createProduct()
{
return new ProductB<T>;
}
};
Why can't you templatize IProductFactory on T as well? That would get rid of your error, and it's no less general. The client is still going to have to know what T is in order to call thecreateProduct method.
Edit Re: comment
In order to do this, you will need to just create a templatized function to create the factory. So:
template<class T> IProductFactory<T>* getProductFactory();
Now your factory is templatized, the createProduct method is no longer a member template. Not sure what your criteria is for returning a ProductAFactory vs. a ProductBFactory but you will either have to pass in a string to choose, have this be a member function of another class that would make the decision, or have multiple free functions but only expose one version or another to a particular client.
This doesn't need a template. Does that eliminate your problem?