I'm struggling with a problem regarding the linking between two derived classes from a template one. Let's say that we have a template base class Param_B which take as parameter one of it's children (Param_S or Param_M). The template parameter of the class Param_B is used further for definition of other local variables( _parent and a callback function _func). For me is necessary to have the Param_S or Param_M for dynamically call of the function.
The problem is that after I create the pointers to the children's and add timers and functions to them I want to have a _link Variable which will enable to exchange information between both children types. E.g. from the Param_S I want to change the timeout of a Param_M timer by using the _link variable. I
#include <stdio.h>
#include <memory>
#include <vector>
class Param_S;
class Param_M;
template <class T>
class Functionn{
Functionn(){};
~Functionn(){};
private:
std::function<void(std::shared_ptr<T>)> _callback;
};
template <class T>
class Timer
{
public:
Timer(){ timeout = 0; };
~Timer(){};
void setTimeout(const int time){ timeout = time; };
std::weak_ptr<Functionn<T>>& getFunction(){ return _func; };
std::weak_ptr<T> getParent(){ return _parent;};
private:
int timeout;
std::weak_ptr<T> _parent;
std::weak_ptr<Functionn<T>> _func;
};
template <class T>
class Param_B {
public:
Param_B(){};
~Param_B(){};
std::vector<std::shared_ptr<Timer<T>>>& getTimers(){
return _timers;
}
void addTimer(std::shared_ptr<Timer<T>> _t){
_timers.push_back(std::move(_t));
}
std::weak_ptr<Param_B> getLink(){
return _link;
}
void setLink(std::weak_ptr<Param_B> link){
_link = link;
}
private:
std::weak_ptr<Param_B> _link;
std::vector<std::shared_ptr<Timer<T>>> _timers;
};
class Param_S : public Param_B<Param_S>
{
public:
Param_S(){ paramS = -2; };
~Param_S(){};
void setValue(){
paramS = 33;
}
int getValue(){ return paramS;};
private:
float paramS;
};
class Param_M : public Param_B<Param_M>
{
public:
Param_M(){ parammM = -4; };
~Param_M(){};
int getValue(){ return parammM; };
private:
int parammM;
};
class sys{
public:
std::vector<std::shared_ptr<Param_S>> getParams(){
return _params;
}
private:
std::vector<std::shared_ptr<Param_S>> _params;
};
class module{
public:
std::vector<std::shared_ptr<Param_M>> getParams(){
return _params;
}
private:
std::vector<std::shared_ptr<Param_M>> _params;
};
void main(){
std::shared_ptr<sys> _sys = std::make_shared<sys>();
_sys->getParams().push_back(std::make_shared<Param_S>());
_sys->getParams()[0]->addTimer(std::make_shared<Timer<Param_S>>());
std::shared_ptr<module> _mod = std::make_shared<module>();
_mod->getParams().push_back(std::make_shared<Param_M>());
_mod->getParams()[0]->addTimer(std::make_shared<Timer<Param_M>>());
_sys->getParams()[0]->setLink(_mod->getParams()[0]); // this not work , the conversion failed
}
Thank you for your help.
You need to have a non-template base for Param_B. It can't involve anything related to the template parameter, but you could have virtual functions here
class Param_B_Base {
public:
virtual ~Param_B_Base() = default;
std::weak_ptr<Param_B_Base> getLink(){
return _link;
}
void setLink(std::weak_ptr<Param_B_Base> link){
_link = link;
}
// an example of possible behaviour
virtual void setTimeouts(const int time) = 0;
// another example of possible behaviour
virtual void invokeHandlers() = 0;
private:
std::weak_ptr<Param_B_Base> _link;
};
template <class T>
class Functionn{
void operator()(std::shared_ptr<T> ptr) { _callback(ptr); }
private:
std::function<void(std::shared_ptr<T>)> _callback;
};
template <class T>
class Timer
{
public:
void setTimeout(const int time){ timeout = time; };
void invoke() { if (auto func = _func.lock()) { if (auto parent = parent.lock() { (*func)(parent); } } }
private:
int timeout = 0;
std::weak_ptr<T> _parent;
std::weak_ptr<Functionn<T>> _func;
};
Then you can have a template for subclasses
template <class T>
class Param_B : public Param_B_Base {
public:
std::vector<std::shared_ptr<Timer<T>>>& getTimers(){
return _timers;
}
void addTimer(std::shared_ptr<Timer<T>> _t){
_timers.push_back(std::move(_t));
}
// The implementation of the virtual methods can know about T
void setTimeouts(const int timeout) override {
for (std::shared_ptr<Timer<T>> timer : _timers) {
timer->setTimeout(timeout);
}
}
void invokeHandlers() override {
for (std::shared_ptr<Timer<T>> timer : _timers) {
timer->invoke();
}
}
private:
std::vector<std::shared_ptr<Timer<T>>> _timers;
};
I would suggest making the link between the two derived classes type-agnostic (i.e. make the link a std::function rather than a pointer to an instance of the other type.
If you would like to keep it as a pointer, your problem is in your use of Param_B within the Param_B template class.
void setLink(std::weak_ptr<Param_B> link)
In the above line, Param_B will refer to the Param_B<Param_M> when the method is called on an instance of Param_B<Param_M>, and it will refer to Param_B<Param_S> when the method is called on an instance of Param_B<Param_S>.
What you need to do is add a second template parameter to Param_B to tell it what the linked derived type is.
template <class T, class L>
class Param_B {
public:
Param_B(){};
~Param_B(){};
std::vector<std::shared_ptr<Timer<T>>>& getTimers(){
return _timers;
}
void addTimer(std::shared_ptr<Timer<T>> _t){
_timers.push_back(std::move(_t));
}
std::weak_ptr<Param_B> getLink(){
return _link;
}
void setLink(std::weak_ptr<Param_B<L, T>> link){
_link = link;
}
private:
std::weak_ptr<Param_B<L, T>> _link;
std::vector<std::shared_ptr<Timer<T>>> _timers;
};
Then you'll need a forward declaration of Param_M so it can be a template parameter for Param_S.
class Param_M;
class Param_S : public Param_B<Param_S, Param_M>
{
...
};
class Param_M : public Param_B<Param_M, Param_S>
{
...
};
Edit:
If you know how the derived types will interact, don't use functions as links; see the answer from #Caleth.
Related
i know there is nothing like virtual template method in C++, but as it seems it is exactly what i need. Is there any workaround i could use? I am thankful for any suggestion.
I would like to add Entities to a vector by a add method, which need to be virtual and also template, how to avoid this?
#include <iostream>
#include <vector>
class EntityBase {
public:
};
class EntityDerived1 : public EntityBase {
public:
};
class EntityDerived2 : public EntityBase {
public:
};
class ContainerBase {
public:
template<typename T>
virtual void add() = 0; // i know this is not allowed!!!
};
class ContainerConcrete : public ContainerBase {
public:
template<typename T>
void add() override { // i know this is not allowed!!!
data.push_back(std::make_shared<T>());
}
void doSecretStuffWithDataHere() {
// ...
}
private:
std::vector<std::shared_ptr<EntityBase>> data;
};
class Engine {
public:
Engine() :
container(std::make_shared<ContainerConcrete>())
{}
ContainerBase& getContainer() {
auto rawPointer = container.get();
return *container;
}
private:
std::shared_ptr<ContainerConcrete> container;
};
int main() {
Engine engine;
ContainerBase& container = engine.getContainer();
container.add<EntityDerived1>();
container.add<EntityDerived2>();
}
Just make add a regular virtual function that takes shared_ptr as a parameter
class ContainerBase {
public:
virtual void add(std::shared_ptr<EntityBase>) = 0;
};
class ContainerConcrete : public ContainerBase {
public:
void add(std::shared_ptr<EntityBase> p) override {
data.push_back(p);
}
// . . .
And then invoke it with make_shared for the desired type:
int main() {
Engine engine;
ContainerBase& container = engine.getContainer();
container.add(std::make_shared<EntityDerived1>());
container.add(std::make_shared<EntityDerived2>());
}
Alternatively you can add a templated overload that invokes make_shared:
virtual void add(std::shared_ptr<EntityBase>) = 0;
template<typename T>
void add() {
add(std::make_shared<T>());
}
I'm modifying a class by adding a data-member that is templated. The code will invariably be using a default template type for the template parameter in all invocations, except for one place. Partially motivated by this, and partially due to a a desire/whim, I do not want to add a template parameter to the class as shown below:
#include <iostream>
template <typename Der>
class A : private Der {
public:
int get() { return Der::get_(); }
};
class B {
protected:
int get_() { return 20; }
};
class C {
protected:
int get_() { return 30; }
};
using Default = B;
template <class T = Default>
class User {
public:
User() {}
A<T>& getMember() { return m_; }
private:
A<T> m_; // This is what I am adding, and exposing param T.
};
int main(int argc, char* argv[]) {
User h;
std::cout<<h.getMember().get()<<std::endl;
}
One solution that I could think of is the use of a sum-type, but this introduces some exception handling code:
class User {
public:
User() : m_(A<Default>()) {}
template <typename T>
User(const T& in) : m_(in) {}
template <typename T>
A<T>& getMember() { return std::get<A<T>>(m_); }
private:
std::variant<A<B>, A<C>> m_;
};
I'm looking for:
A name for what I am trying to do, if it exists.
Ways in which I can accomplish what I desire.
This is not an answer, as I don't find the virtual function call completely satisfactory, but, as progress, another option I can share is type-erasure using an inner base class.
Something like:
#include <iostream>
#include <memory>
class User {
public:
template <class T>
User(T&&) : m_(new Internal<T>()) {}
int doOnMember() { return m_->doOnMember(); }
private:
class InternalBase {
public:
virtual int doOnMember() = 0;
};
template <typename T>
class Internal : public InternalBase {
public:
Internal() {}
int doOnMember() { return m_.get(); }
private:
A<T> m_;
};
private:
std::shared_ptr<InternalBase> m_;
};
int main(int argc, char* argv[]) {
User h(B{});
std::cout<<h.doOnMember()<<std::endl;
User h1(C{});
std::cout<<h1.doOnMember()<<std::endl;
}
I have problem with storing templates class in the base of two objects.
Say I have generalized class named ObjectManager Defined as:
template<typename T>
class ObjectManager
{}
And I have a base class like:
class MediaSample
{
public:
MediaSample(ObjectManager<?>* manager){}
private:
ObjectManager<?> mMediaSampleManager;
}
Now I declare another two drived class from MediaSample, say:
class AudioSample : public MediaSample
{
public:
AudioSample() : MediaSample(new ObjectManager<AudioSample>()){}
//...
}
public class VideoSample : public MediaSample
{
public:
VideoSample() : MediaSample(new ObjectManager<VideoSample>())
//...
}
My problem is type of manager, input parameter of MediaSample class.
Which type must be place instead of question mark character? (Audio, Video or what?)
for more clarification i posted complete source of ObjectManager
note that object manager is a poll of media sample objects and media sample can be audio or video
class BaseMediaSampleManager
{
public:
~BaseMediaSampleManager(){}
virtual INT initialize(INT objectCount) = 0;
protected:
private:
};
template<typename T>
class MediaSamppleManager : public BaseMediaSampleMnager //(based on user2079303 advise)
{
protected:
MediaSamppleManager(void);
MediaSamppleManager(const MediaSamppleManager& manager);
MediaSamppleManager& operator = (const MediaSamppleManager& rhs);
public:
virtual ~MediaSamppleManager(void);
static MediaSamppleManager<T>* instance();
INT initialize(INT objectCount);
// take existing object from object pool and return that object
INT aquireObject(T** object);
// take back in use object to object pool
INT release(T* object);
private:
std::list<T*> mPooledSamples;
INT32 mPooledObjectCount;
INT32 mInUseObjects;
Mutex mPooledSamplesMutex;
static Mutex mSampleManagerObjectMutex;
static MediaSamppleManager<T>* mSampleManagerObject;
};
template<typename T>
Mutex MediaSamppleManager<T>::mSampleManagerObjectMutex;
template<typename T>
MediaSamppleManager<T>* MediaSamppleManager<T>::mSampleManagerObject = NULL;
template<typename T>
MediaSamppleManager<T>* MediaSamppleManager<T>::instance()
{
if (mSampleManagerObject == NULL)
{
ScopedLock<Mutex> guard(mSampleManagerObjectMutex);
if (mSampleManagerObject == NULL)
{
MediaSamppleManager<T>* temp = new MediaSamppleManager<T>();
mSampleManagerObject = temp;
}
}
return mSampleManagerObject;
}
template<typename T>
MediaSamppleManager<T>& MediaSamppleManager<T>::operator=(const MediaSamppleManager<T>& rhs)
{
}
template<typename T>
MediaSamppleManager<T>::MediaSamppleManager(const MediaSamppleManager<T>& manager)
{
}
template<typename T>
INT MediaSamppleManager<T>::release(T* object)
{
ScopedLock<Mutex> guard(mPooledSamplesMutex);
mPooledSamples.push_back(object);
mInUseObjects--;
}
template<typename T>
INT MediaSamppleManager<T>::aquireObject(T** object)
{
ScopedLock<Mutex> guard(mPooledSamplesMutex);
if (mInUseObjects == mPooledObjectCount)
{
// do we need waiting until new sample become available? or
// is it required to create new sample when no free sample exist in pool?
return 2;
}
else
{
T* temp = 0;
temp = mPooledSamples.front();
*object = temp;
mPooledSamples.pop_front();
mInUseObjects++;
}
return 1;
}
template<typename T>
INT MediaSamppleManager<T>::initialize(INT objectCount)
{
if (objectCount<=0)
{
return -1;
}
mPooledObjectCount = objectCount;
mPooledSamples.resize(objectCount);
for (int i = 0 ; i< objectCount ; i++)
{
T* temp = new T(this);
mPooledSamples.push_back(temp);
}
return 1;
}
template<typename T>
MediaSamppleManager<T>::~MediaSamppleManager(void)
{
std::cout << "MediaSampleManager Destroyed \n";
}
template<typename T>
MediaSamppleManager<T>::MediaSamppleManager(void)
:mPooledObjectCount(0)
,mInUseObjects(0)
{
}
class MediaSample :
class MediaSample
{
public:
// create empty media sample
MediaSample(BaseMediaSampleManager* manager);
virtual ~MediaSample(void);
virtual INT32 rate() = 0;
virtual double frameSize() = 0;
// data size of media sample
virtual INT size();
UINT* data();
ULONG samplingTime();
INT32 addRef();
INT32 release();
private:
UINT8* mMediaSampleBuffer;
// The time sample captured
ULONG mTimestamp;
// length of data
INT mDataLength;
INT mRefCount;
BaseMediaSampleManager* mMediaSampleManager;
};
class AudioSample :
class PMCAPI AudioSample
:public MediaSample/*<AudioSample>*/
{
public:
AudioSample(MediaSamppleManager<AudioSample>* manager);
~AudioSample();
virtual INT32 rate();
virtual double frameSize();
virtual INT size();
protected:
private:
// in 8,16 KHZ
INT32 mSampleRate;
// Mono or Stereo
INT mChannels;
// Used format ex: PCM,G729,G723,G711A,G711U
INT mCodec;
// ex : 8 bit , 16 bit
INT mBitsPerSample;
};
It's can get pretty difficult to mix compile time (templates) and runtime polymorphism (inheritance). What you can do:
a) Make the base class a template
template <class T>
class MediaSample {
ObjectManager<T> mMediaSampleManager;
};
class AudioSample : public MediaSample<AudioSample>
In this case AudioSample and VideoSample will not have a common base class, which may not be what you want. Alternatively, you can
b) Give ObjectManager a non-template base class (an interface)
class BaseManager{
virtual ~BaseManager(){}
// pure virtual functions that ObjectManager implements
};
template<typename T>
class ObjectManager: public BaseManager{
// implementation
};
class MediaSample {
BaseManager mMediaSampleManager;
// ...
};
class AudioSample: public MediaSample {
public:
AudioSample() : MediaSample(new ObjectManager<AudioSample>()){}
Also, note that if your MediaSample constructor accepts a pointer to newly constructed ObjectManager and you presumably copy that to the member object, you must remember to delete the pointer or it'll leak. You should probably pass by value instead.
How about making MediaSample a template:
template <typename T>
class MediaSample
{
public:
MediaSample(ObjectManager<T>* manager){}
private:
ObjectManager<T> mMediaSampleManager;
};
This way you can have different kinds of MediaSample without the neeed of having derived classes AudioSample and VideoSample.
In this case MediaSampleneeds to be a template
template<typename T>
class MediaSample
{
public:
MediaSample(ObjectManager<T>* manager): mMediaSampleManager(manager) {}
private:
ObjectManager<T>* mMediaSampleManager;
}
and XxxSample has to inherit from the specialized MediaSample
class AudioSample : public MediaSample<AudioSample>
{
public:
AudioSample() : MediaSample(new ObjectManager<AudioSample>()){}
...
}
I'm trying to figure out a way to dynamically cast an instance of a child class to its parent in a somewhat difficult set of conditions.
Specifically, I have a an object hierarchy that looks something like (I've simplified a lot, so if something doesn't make sense, it might be due to the simplification):
class Object {
public:
virtual ~Object() {}
};
// shown just to give an idea of how Object is used
class IntObject: public Object {
protected:
int value;
public:
IntObject(int v) { value = v; }
int getValue() { return value; }
};
template <class T>
class ObjectProxy: public Object {
protected:
T *instance;
public:
ObjectProxy(T *instance): instance(instance) {}
T *getInstance() { return instance; }
};
The ObjectProxy class essentially acts as a wrapper to allow other types to be used in the Object hierarchy. Specifically, it allows pointers to class instances to be kept, and used later when invoking the instance's methods. For example, suppose I have:
class Parent {
protected:
int a;
public:
Parent(int v) { a = v; }
virtual ~Parent() {}
void setA(int v) { a = v; }
int getA() { return a; }
};
class Child: public Parent {
protected:
int b;
public:
Child(int v1, int v2): Parent(v1) { b = v2; }
void setA(int v) { b = v; }
int getB() { return b; }
};
I might use them in the following situation:
template <typename C>
void callFn(std::list<Object *> &stack, std::function<void (C*)> fn) {
Object *value = stack.front();
stack.pop_front();
ObjectProxy<C> *proxy = dynamic_cast<ObjectProxy<C> *>(value);
if (proxy == nullptr) {
throw std::runtime_error("dynamic cast failed");
}
fn(proxy->getInstance());
}
void doSomething(Parent *parent) {
std::cout << "got: " << parent->getA() << std::endl;
}
int main() {
std::list<Object *> stack;
// this works
stack.push_back(new ObjectProxy<Child>(new Child(1, 2)));
callFn<Child>(stack, doSomething);
// this will fail (can't dynamically cast ObjectProxy<Child> to ObjectProxy<Parent>)
stack.push_back(new ObjectProxy<Child>(new Child(1, 2)));
callFn<Parent>(stack, doSomething);
}
As noted in the above comments, this code fails for a known reason. In the sample code, it's easy to avoid invoking callFn<Parent>(stack, doSomething). However, in my real code, I am using the signature of the function to determine type, and if its a method for the parent class, that will automatically be used for the template parameter.
My question is if there is any way to achieve the dynamic cast from ObjectProxy from an object of type of ObjectProxy. Part of the complication comes from the fact that in the function callFn, you only have the Parent type and not the child type.
I looked into using type-erasure via boost::any (i.e. ObjectProxy stops being templated, and instead has boost::any instance), but still ran into problems when it came to dynamic-casting (boost::any_cast is static). I did find mention to a dynamic_any on SO, but have not gotten it to work properly yet.
Any help or insight into the problem is greatly appreciated.
The dynamic cast is failing because the classes that are instantiations of ObjectProxy do not share the same hierarchy as the types given in the parameterisation of ObjectProxy. I see two approaches that may help. One, you make the types given to ObjectProxy share a single common base class and move the dynamic cast away from ObjectProxy and onto the instances.
namespace approach2 {
struct object_t {
virtual ~object_t() { }
};
struct required_base_t {
virtual ~required_base_t() { }
};
class object_proxy_base_t : public object_t {
required_base_t* instance_;
public:
object_proxy_base_t(required_base_t* i) : instance_ (i) { }
template <class T>
T* cast_to() const
{
return dynamic_cast<T*>(instance_);
}
};
template <class value_t>
class object_proxy_t : public object_proxy_base_t {
value_t* instance_;
public:
object_proxy_t(value_t* i)
: object_proxy_base_t (i),
instance_ (i)
{
}
};
template <class value_t>
object_t* new_with_proxy(value_t const& value)
{
return new object_proxy_t<value_t>(new value_t(value));
}
struct parent_t : required_base_t {
virtual ~parent_t() { }
};
struct child_t : parent_t {
virtual ~child_t() { }
};
void f()
{
object_t* a = new_with_proxy(parent_t());
object_t* b = new_with_proxy(child_t());
std::cout
<< dynamic_cast<object_proxy_base_t*>(a)->cast_to<parent_t>() << '\n' // works
<< dynamic_cast<object_proxy_base_t*>(b)->cast_to<parent_t>() << '\n' // works
;
}
}
This approach is not possible if you cannot change the base classes of all types used by ObjectProxy. Which leads to the second solution where you make ObjectProxy instantiations have the same hierarchy as the types used to parameterise it.
namespace approach3 {
struct object_t {
virtual ~object_t() { }
};
struct empty_t {
template <class T>
empty_t(T*) { }
};
template <class value_t>
class object_proxy_t : public virtual object_t {
value_t* instance_;
public:
object_proxy_t(value_t* i) : instance_ (i) { }
};
template <class value_t, class base_t>
class object_proxy_sub_t :
public object_proxy_t<value_t>,
public base_t {
public:
object_proxy_sub_t(value_t* i)
: object_proxy_t<value_t>(i),
base_t (i)
{
}
};
template <class base_t, class value_t>
object_t* new_with_proxy(value_t const& value)
{
return new object_proxy_sub_t<value_t, base_t>(new value_t(value));
}
struct parent_t {
virtual ~parent_t() { }
};
struct child_t : parent_t {
virtual ~child_t() { }
};
void f()
{
object_t* a = new_with_proxy<empty_t>(parent_t());
object_t* b = new_with_proxy<object_proxy_t<parent_t> >(child_t());
std::cout
<< dynamic_cast<object_proxy_t<parent_t>*>(a) << '\n' // works
<< dynamic_cast<object_proxy_t<parent_t>*>(b) << '\n' // works
;
}
}
This approach places fewer requirements on the types involved but means more work to keep the hierarchies in sync.
Building off of Bowie Owen's first answer, I realized that while the types given would likely not be derived from the same class (it's a library), I could force that to occur:
struct ObjectProxyBaseType {
virtual ~ObjectProxyBaseType() {}
};
template <class T>
class ObjectProxyType: public ObjectProxyBaseType, public T {
public:
// allow construction via parameters
template <typename... Args>
ObjectProxyType(Args &&... args): T(std::move(args)...) {}
// or construction via copy constructor
ObjectProxyType(T *t): T(*t) {}
virtual ~ObjectProxyType() {}
};
Thus, if I have class Child, I can create an instance of ObjectProxyType<Child>, which causes it to also inherit ObjectProxyBaseType. The rest of the code follows Bowie's suggestion:
class ObjectProxy: public Object {
protected:
ObjectProxyBaseType *instance;
public:
template <typename T>
ObjectProxy(ObjectProxyType<T> *i) {
instance = i;
}
template <typename T>
ObjectProxy(T *value) {
instance = new ObjectProxyType<T>(value);
}
template <typename T>
T *castTo() const {
return dynamic_cast<T *>(instance);
}
};
And an example of code that works:
int main() {
std::list<Object *> stack;
stack.push_back(new ObjectProxy(new Child(1, 2)));
callFn<Child>(stack, doSomething);
stack.push_back(new ObjectProxy(new Child(5, 6)));
callFn<Parent>(stack, doSomething);
}
I've had to do something somewhat similar recently. I've used an approach which worked for me, but might not be appropriate in this case; use your discretion. This hinges on the fact that you (or the person extending this code, if any) have full knowledge of what hierarchies will be used as template parameters.
So let's say these hierarchies are the following:
class Parent1
class Child1: public Parent1
class Child11: public Child1
...
class Parent2
class Child2: public Parent2
...
Then you build a holder class. It is a bit complicated for a simple reason - my compiler doesn't support default template parameters on functions, so I am using helper structs to enable SFINAE.
This class needs to be able to hold objects belonging to all hierarchies (through a base class pointer).
class TypeHolder
{
template<class T, class E=void>
struct GetHelper
{
static T* Get(const TypeHolder* th) { return nullptr; }
//you can actually add code here to deal with non-polymorphic types through this class as well, if desirable
};
template<class T>
struct GetHelper<T, typename std::enable_if<std::is_polymorphic<T>::value, void>::type>
{
static T* Get(const TypeHolder* th)
{
switch(th->type)
{
case P1: return dynamic_cast<T*>(th->data.p1);
case P2: return dynamic_cast<T*>(th->data.p2);
//and so on...
default: return nullptr;
}
}
};
template<class T, class E=void>
struct SetHelper
{
static void Set(T*, TypeHolder* th) { th->type = EMPTY; }
};
template<class T>
struct SetHelper<T, typename std::enable_if<std::is_polymorphic<T>::value, void>::type>
{
static void Set(T* t, TypeHolder* th)
{
th->data.p1 = dynamic_cast<Parent1*>(t);
if(th->data.p1) { th->type = P1; return; }
th->data.p2 = dynamic_cast<Parent2*>(t);
if(th->data.p2) { th->type = P2; return; }
//...and so on
th->type = EMPTY;
}
};
public:
TypeHolder(): type(EMPTY) { }
template<class T>
T* GetInstance() const
{
return GetHelper<T>::Get(this);
}
template<class T>
void SetInstance(T* t)
{
SetHelper<T>::Set(t, this);
}
private:
union
{
Parent1* p1;
Parent2* p2;
//...and so on
} data;
enum
{
EMPTY,
P1,
P2
//...and so on
} type;
};
By the way, the reason we need the SFINAE trick is because of the dynamic_casts, which will not compile on non-polymorphic types.
Now all you need to do is modify your classes just a little bit :)
class ObjectProxyBase
{
public:
virtual const TypeHolder& GetTypeHolder() const = 0;
};
template<class T>
class ObjectProxy: public Object, public ObjectProxyBase
{
T* instance;
static TypeHolder th; //or you can store this somewhere else, or make it a normal (but probably mutable) member
public:
ObjectProxy(T* t): instance(t) { }
T* getInstance() const { return instance; }
const TypeHolder& GetTypeHolder() const { th.SetInstance(instance); return th; }
//... and the rest of the class
};
template<class T>
TypeHolder ObjectProxy<T>::th;
I hope this code is actually correct, since I mostly typed it into the browser window (mine used different names).
And now for the final piece: the function.
template <typename C>
void callFn(std::list<Object *> &stack, std::function<void (C*)> fn) {
Object *value = stack.front();
stack.pop_front();
ObjectProxyBase *proxy = dynamic_cast<ObjectProxyBase *>(value);
if (proxy == nullptr) {
throw std::runtime_error("dynamic cast failed");
}
C* heldobj = proxy->GetTypeHolder().GetInstance<C>(); //I used to have a dynamic_cast here but it was unnecessary
if (heldobj == nullptr) {
throw std::runtime_error("object type mismatch");
}
fn(heldobj);
}
You only need to use this approach for hierarchies, and can still use the dynamic_cast directly to ObjectProxy<C>* in other cases (essentially, you'll want to try both and see if one succeeds).
I hope this is at least a little bit helpful.
template <typename T>
class BaseQueue
{
public :
virtual void push_back(T value) = 0;
//other virtual methods
};
template <typename T>
class BaseDeque: public virtual BaseQueue<T>
{
public:
virtual void push_front(T value) = 0;
//other virtual methods
};
//Realisation
template <typename T>
class VectorQueue: public BaseQueue<T>
{
typedef typename std::vector<T> array;
private: array adata;
public:
VectorQueue()
{
adata = array();
}
void push_back(T value)
{
adata.push_back(value);
}
};
template <typename T>
class VectorDeque: virtual public VectorQueue<T>, virtual protected BaseDeque<T>//,
{
void push_front(T value)
{
VectorQueue::adata.push_front(value);
}
};
int _tmain(int argc, _TCHAR* argv[])
{
VectorDeque<int> vd = VectorDeque<int>();//here is a error
int i;
std::cin >> i;
return 0;
}
I have such error: "C2259: 'VectorDeque' : cannot instantiate abstract class ...". How can I fix it? Class VectorQueue has realize every virtual method of BaseQueue class already. But the compiler doesn't know it. The only way I see is to write something like this:
template <typename T>
class VectorDeque: virtual public VectorQueue<T>, virtual protected BaseDeque<T>//,
{
void push_front(T value)
{
VectorQueue::adata.push_front(value);
}
void push_back(T value)
{
VectorQueue::push_back(value);
}
//repeat it fo every virtual method of BaseQueue class (interface)
};
But it's awful.
push_back from BaseQueue isn't implemented on the BaseDeque side of the inheritance chain, and thus the childmost class is still abstract.
I think you're trying to force a class relationship here that shouldn't exist. Note how in the standard library deque and vector are distinct container types and things like queue adapt those containers to very precise interfaces rather than trying to inherit.
Even if you solve your diamond issue (or follow #Mark B's advice and keep them separate), you have a few other issues in there:
template <typename T>
class VectorQueue: public BaseQueue<T>
{
typedef typename std::vector<T> array;
private: array adata; // if this is private, VectorDeque can't reach it
public:
// constructors have an initializer section
// member variables should be initialized there, not in the body
VectorQueue()
// : adata() // however, no need to explicitly call default constructor
{
// adata = array();
}
};
template <typename T>
class VectorDeque: virtual public VectorQueue<T>, virtual protected BaseDeque<T>
{
void push_front(T value)
{
// if adata is protected, you can just access it. No need for scoping
/*VectorQueue::*/ adata.push_front(value);
// Error: std::vector doesn't have a method push_front.
// Perhaps you meant to use std::list?
}
};
Multiple inheritance and static polymorphism are of help, for instance:
// Abstract bases
template <typename T, typename Val>
class BaseQueue
{
public :
void push_back(Val val)
{
static_cast<T*>(this)->push_back(val);
}
// ...
};
template <typename T, typename Val>
class BaseDeque
{
public:
void push_front(Val val)
{
static_cast<T*>(this)->push_front(val);
}
// ...
};
// Concrete class
#include <deque>
template <typename Val>
class QueueDeque:
public BaseQueue<QueueDeque<Val>, Val>,
public BaseDeque<QueueDeque<Val>, Val>
{
std::deque<Val> vals;
public:
void push_front(Val val)
{
vals.push_front(val);
}
void push_back(Val val)
{
vals.push_back(val);
}
// etc..
};
int main()
{
QueueDeque<int> vd;// no more error
vd.push_front(5);
vd.push_back(0);
return 0;
}