Reputation: 1
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.
Upvotes: 0
Views: 96
Reputation: 804
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.
Upvotes: 0
Reputation: 62636
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;
};
Upvotes: 1