Extending a CRTP template functionality - c++

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>
{};

Related

Object generation from different id types slow compilation

I have a of templated class that can generate an object instance from an ID. The context is networking code with object replication.
The code below shows a way that I can manage to do this, but it has the drawback of beeing very slow in compilation.
Does anyone know a "better" way to achieve what my example shows.
I'm not sure how to make this question more clear, I hope the code speaks for itself.
I have looked at extern templates, but I do not see how to apply that to templated functions in templated classes. If anyone knows how to do that, that would solve the issue.
Alternatively a way to fix the ambiguous problem of MyRegistersSimple would also be greatly helpfull!
template<typename ID, typename Base>
class Register
{
public:
void create(ID id) { m_types.at(id).second(); }
private:
std::map<ID, std::function<std::unique_ptr<Base>(ID)>> m_types;
};
template<typename tag>
struct ID { int value; };
class ABase {};
class BBase {};
class CBase {};
using ID_A = ID<struct ID_A_TAG>;
using ID_B = ID<struct ID_B_TAG>;
using ID_C = ID<struct ID_C_TAG>;
class MyRegistersSimple :
public Register<ID_A, ABase>,
public Register<ID_B, BBase>,
public Register<ID_C, CBase>
{
};
template<typename... Registers>
class MultiRegister : public Registers...
{
public:
template<typename ID>
void create(ID)
{
// lots of complex template code to find the correct Register from 'Registers...'
// and call 'create' on it
// this makes compilation very slow
}
};
class MyRegistersComplex : public MultiRegister<
Register<ID_A, ABase>,
Register<ID_B, BBase>,
Register<ID_C, CBase>>
{};
void test()
{
MyRegistersSimple simple;
simple.create(ID_A(0)); // -> ambiguous, doest not compile
MyRegistersComplex complex;
complex.create(ID_A(0)); // -> very slow compilation
}
Basic solution
Bring all the bases into scope via using:
// a helper to avoid copy pasting `using`s
template<typename... Registers> struct MultiRegister : Registers... { using Registers::create...; };
class MyRegisters : public MultiRegister<
Register<ID_A, ABase>,
Register<ID_B, BBase>,
Register<ID_C, CBase>>
{};
void test() {
MyRegisters registers;
registers.create(ID_A(0)); // IDE shows that `Register<ID<ID_A_TAG>, ABase>` is chosen
}
I hope the built-in overload resolution is faster than "lots of complex template code" in the ...Complex version.
Offtopic improvement
I didn't like that manual Register<ID_A, ABase> ID_x <-> xBase dispatch and dummy ID_x_TAGs, so I removed all of that (if using xBase as the ID's template parameter is fine). Then Register<ID_A, ABase>, Register<ID_B, BBase> etc. become
template<typename Base> using MakeRegister = Register<ID<Base>, Base>;
and the code suggested above is just (test() omitted - it's the same)
template<typename... Registers> struct MultiRegister : Registers... { using Registers::create...; };
template<typename... Bases> using MakeMultiRegister = MultiRegister<MakeRegister<Bases>...>;
class MyRegisters : public MakeMultiRegister<ABase, BBase, CBase> {};

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.

C++ Template Specialization with Inheritance

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>.

How can I use templated generic constraints in C++/CLI

I'm having some trouble figuring out if I can use templated generic constraints in C++/CLI. here's an example
template<typename T>
public ref class wrapped
{
public:
T* t;
T doTthing(){return *t;}
};
Here's a simple templated managed class, wrapping an unmanaged type T. I can use this class as a constraint for a generic
// works
generic<class genclass> where genclass : wrapped<int>
public ref class testclass3
{
public:
genclass gc;
int test()
{
return gc->doTthing();
}
};
This works fine. What I can't figure out is how to preserve both the templating and the generic, i.e.
//Does Not Work!
template<typename T>
generic<class genclass> where genclass : wrapped<T>
public ref class testclass4
{
public:
genclass gc;
T test()
{
return gc->doTthing();
}
};
Is this kind of thing possible?
You can't mix templates with generics in the same declaration.
The class should either be templated or generic. See: Managed Templates
Templates are mush more expressive, so i would suggest you use them instead.
If you want to simulate a constraint (same technique would work in c++ by the way..) you could do:
template<class T, class GENCLASS>
public ref class testclass4
{
private:
typedef typename GENCLASS::wrapped<T> Constraint1;
public:
genclass gc;
T test()
{
return gc->doTthing();
}
};
If the class does not inherit from wrapped<T> then the typedef declaration will fail saying that "wrapped is not a member of GENCLASS".

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?