Template Specialization over derived class - c++

I don't know if it is possible, I checked on StackOverflow, I found a lot of stuff but nothing that really fit my problem (or I don't see the relation).
What I'd like to do is something like that:
class Bean
{
public:
Bean(){}
virtual ~Bean(){}
template <class T>
bool set_(T){return false;}
template <class T>
bool get_(T&){return false;}
};
template <class T>
class GenericBean: public Bean
{
protected:
T type;
};
class Prova : public GenericBean<int>
{
public:
Prova(){type = 0;}
template<int> bool set_(int value){ type=value;}
template<int> bool get_(int& value){value = type;}
};
I'd like to have on object like Prova, cast to Bean and get the specialized function,
What I want to do is something like this:
#include <vector>
#include "Bean.h"
using namespace std;
class VirtualMessage
{
public:
VirtualMessage(void){}
virtual ~VirtualMessage(void){}
template <class ReturnValue, class Item>
bool Get(ReturnValue & val)
{
for(size_t i = 0; i < m_vData.size(); i++)
{
if(m_vData[i].get_<ReturnValue>(val))
return true;
}
}
template <class Item, class Value>
bool Set(Value val)
{
Item bean;
if(bean.set_<Value>(val))
{
m_vData.push_back(bean);
return true;
}
return false;
}
protected:
vector<Bean> m_vData;
};
Main:
#include "VirtualMessage.h"
#include "Bean.h"
int main()
{
VirtualMessage msg;
if(msg.Set<Prova ,int>(4))
printf("Test 1 passed");
}
this code doesn't compile
Maybe nobody will use it, but I wrote something that fits my need. It's not perfect, I have to work on it but is a begin:
#define UNIQUE(T) unsigned int GetID(){return UniqueType<T>::id();}
struct UniqueTypeBase
{
static unsigned int _ids;
};
unsigned int UniqueTypeBase::_ids = 0;
template <class T>
struct UniqueType : public UniqueTypeBase
{
static const unsigned int id()
{
static unsigned int typeId = 0;
if (typeId == 0)
typeId = ++_ids;
return typeId;
}
};
template <class T>
class TemplateBean
{
public:
T m_tValue;
template<class T> set_(T){return false;}
template<class T> get_(T&){return false;}
bool set_(T value){ m_tValue = value; return true;}
bool get_(T& value) { value = m_tValue;return true;}
};
class Prova : public TemplateBean<int>
{
public:
UNIQUE(Prova)
Prova(){m_tValue = 0;}
};
class Prova2 : public TemplateBean<float>
{
public:
UNIQUE(Prova2)
Prova2(){m_tValue = 0;}
};
class VirtualMessage
{
public:
VirtualMessage(void){}
virtual ~VirtualMessage(void){}
template <class Item, class ReturnValue>
bool Get(ReturnValue & val)
{
Item a;
map<unsigned int, void*>::iterator it;
it = m_TagMap.find(a.GetID());
if(it != m_TagMap.end())
{
Item* pItem = reinterpret_cast<Item*>(it->second);
if(pItem->get_(val))
return true;
}
return false;
}
template <class Item, class Value>
bool Set(Value val)
{
Item* pBean = new Item();
if(pBean->set_(val))
{
m_TagMap[pBean->GetID()] = (void*)pBean;
return true;
}
return false;
}
protected:
map<unsigned int, void*> m_TagMap;
};
Test Main:
int main()
{
VirtualMessage msg;
if(msg.Set<Prova ,int>(4))
printf("Test 1 passed\n");
if(!msg.Set<Prova,float>(4.00))
printf("Test 2 succed\n");
if(msg.Set<Prova2,float>(4.00))
printf("Test 3 succed\n");
int a=0;
if(msg.Get<Prova>(a))
printf("%d = 4...if 4=4 test passed\n",a);
float b=0;
if(msg.Get<Prova2>(b))
printf("%f = 4...if 4=4 test passed\n",b);
getchar();
}

I think you misunderstood the use of templates.
Templates are blueprints to build classes or methods, that the compiler use to produce real classes and methods (which is called instantiation).
As such, they are purely a compile-time facility. Therefore, they cannot be virtual, and thus overloading a template method in a derived class does not mean what you expect. It hides the base class method when used from derived (statically) but you still call the base class method if you use a reference or pointer to the base class.
What you are trying to achieve is, unfortunately, impossible with templates: it requires a runtime check.
Furthermore, you are using a std::vector<Bean> which will not work as intended. Polymorphic types shall not be manipulated by values in C++, you need a std::vector< std::unique_ptr<Bean> > or boost::ptr_vector<Bean>...
I would recommend reading a good C++ primer before attempting the kind of task you have set yourself upon. You need a basic introduction to C++ paradigms... and gotchas. And there are a lot of gotchas.

Related

C++ - "unspecialized class template" in unordered_map with shared_ptr to template class

I have a class UISceneParams and I use it to store some parameters that I want to send over to a UIScene. It contains a unordered_map of shared_ptrs to DataParam instances.
The problem is that my DataParam must use a template and feature multiple data types.
Is there any way I can make the unordered_map use multiple data types of DataParams?
I currently call this like this:
UISceneParams p;
p.AddParam<int>("test_value", 123);
p.AddParam<int>("test_value2", 456);
and in my scene I get the parameters using the GetParam<T> method, like this:
int value1 = p.GetParam<int>("test_value", 0);
int value2 = p.GetParam<int>("test_value2", 0);
I've been trying many ways to circumvent the errors, but I am a beginner with templates in C++. Can someone get me on the right track?
UISceneParams.h
#pragma once
#include <string>
#include <unordered_map>
#include <memory>
using namespace std;
template <typename T>
class DataParam {
public:
DataParam(string t, T v) {
_tag = t;
_val = v;
}
T Value() const {
return _val;
}
string Tag() const {
return _tag;
}
private:
string _tag;
T _val;
};
class UISceneParams {
public:
bool HasParam(string tag) {
return params.find(tag) != params.end();
}
template <typename T>
void AddParam(string tag, T value) {
if (HasParam(tag)) params.erase(tag);
params.insert({ tag, make_shared<DataParam>(tag, value) });
}
template <typename T>
T GetParam(string tag, T def_value) {
if (!HasParam(tag)) return def_value;
auto p = params.find(tag)->second;
return p->Value;
}
private:
unordered_map<string, shared_ptr<DataParam>> params;
};
Edit: Final code
#pragma once
#include <string>
#include <unordered_map>
#include <memory>
using namespace std;
class IDataParam
{
public:
virtual ~IDataParam() = default;
};
template <typename T>
class DataParam : public IDataParam {
public:
DataParam(string t, T v) {
_tag = t;
_val = v;
}
T Value() const {
return _val;
}
string Tag() const {
return _tag;
}
private:
string _tag;
T _val;
};
class UISceneParams {
public:
bool HasParam(string tag) {
return params.find(tag.data()) != params.end();
}
template <typename T>
void AddParam(string tag, T value) {
if (HasParam(tag)) params.erase(tag);
params.insert({ tag, make_shared<DataParam<T>>(tag, value) });
}
template <typename T>
T GetParam(string tag, T def_value) {
if (!HasParam(tag)) return def_value;
auto p = dynamic_cast<const DataParam<T> &>(*params.find(tag)->second);
return p.Value();
}
private:
unordered_map<string, shared_ptr<IDataParam>> params;
};
You could make your DataParam inherit from a marker interface like IDataParam, where the interface is just like
class IDataParam
{
virtual ~IDataParam() = default;
};
You could then store all your params as unordered_map<string, shared_ptr<IDataParam>> since they all have the same base type.
Then when getting the param, you just get the IDataParam first by the string key. And then you do a static_cast<const DataParam<T> &>(*gotParam) for example to cast it down to the correct templated DataParam type before returning.
Of course this would not work if you have multiple params with the same key but different T, of you might also run into trouble if you get a param as a type that it is not, to circumvent this issue you could use dynamic_cast though

Cast a polymorphic smart pointer object

I implemented the following smart pointer template class:
#ifndef __ProjectManager__mSharedPtr__
#define __ProjectManager__mSharedPtr__
#include <stdio.h>
#include "RefCount.h"
template <class T>
class mSmartPtr {
T *data;
RefCount *rc;
public:
mSmartPtr(T* srcPtr);
mSmartPtr(const mSmartPtr&);
~mSmartPtr();
T* operator->() const;
T& operator*() const;
mSmartPtr<T>& operator=( mSmartPtr&);
mSmartPtr<T> operator()(mSmartPtr&);
};
template<class T>
mSmartPtr<T> mSmartPtr<T>::operator()(mSmartPtr<T>& src) {
return dynamic_cast<??>(src);
}
template <class T>
mSmartPtr<T>::mSmartPtr(T *srcPtr):
data(srcPtr) {
rc = new RefCount();
rc->add();
}
template<class T>
mSmartPtr<T>::~mSmartPtr() {
if (rc->remove() == 0) {
delete data;
delete rc;
}
}
template<class T>
mSmartPtr<T>::mSmartPtr(const mSmartPtr<T> &src):
data(src.data), rc(src.rc) {
rc->add();
}
template <class T>
T* mSmartPtr<T>::operator->() const {
return data;
}
template<class T>
T& mSmartPtr<T>::operator*() const {
return &data;
}
template <class T>
mSmartPtr<T>& mSmartPtr<T>::operator=( mSmartPtr<T> &src) {
if (this != &src) {
if (rc->remove() == 0) {
delete data;
delete rc;
}
data = src.data;
rc = src.rc;
rc->add();
}
return *this;
}
#endif /* defined(__ProjectManager__mSharedPtr__) */
let's say my application contains the following classes:
class Base
{
protected:
...
public:
virtual ~Base() =0;
...
};
class Derived1 : public Base
{
protected:
...
public:
virtual ~Derived1() {}
...
};
class Derived2 : public Base
{
protected:
...
public:
virtual ~Derived2() {}
...
};
and I need store data at the following way:
int int main(int argc, char const *argv[])
{
std::vector<mSmartPtr<Base>> v;
mSmartPtr<Derived1> d1 = foo();
v.push_back(d1);
return 0;
}
I need to fix somehow the cast operator, but how? how do I get the base class in the dynamic cast?
#Guvante
Your code did not work , I modified it as follows but I don't know if will work well
template<class T>
mSmartPtr<T> mSmartPtr<T>::operator ()(mSmartPtr<T>& src) {
mSmartPtr<T> retVal(dynamic_cast<T*>(src.data));
retVal.rc = src.rc;
retVal.rc.Add();
return retVal;
}
I think there is a better alternative to this. Unless you have a different location where you need to be able to do this, you can avoid the headache by changing the way you create the object.
int main(int argc, char const *argv[])
{
std::vector<mSmartPtr<Base>> v;
mSmartPtr<Base> d1 = static_cast<Base*>(foo());
v.push_back(d1);
return 0;
}
Just avoid creating an mSmartPtr that is typed differently than your vector.
In your conversion method extract the underlying pointer and cast it then put it into the new smart pointer. Don't forget to copy the RefCount and ensure that your target class has a virtual destructor (so the correct one gets called no matter which smart pointer gets dispossed last).
I couldn't figure out how to define it externally but an inline definition worked.
//In the definition, replacing this line
//mSmartPtr<T> operator()(mSmartPtr&)
template<class Tdest>
operator mSmartPtr<Tdest>() {
mSmartPtr<Tdest> retVal(static_cast<Tdest*>(data));
retVal.rc = rc;
retVal.rc.Add();
return retVal;
}
In theory you could also add a version that takes a r-value if you are using C++11 but I think that would take a little work to do correctly so I avoided it.

How to use an integer id to identify a class in a class hierarchy automatically?

For example, I have a base class A and its sub-classes B, C and so on. B and C can also has its sub-classes. The structure is a tree with root A. And each class in the tree is assigned a different integer to identify itself. There is no restriction on the integer id's values and orders. Just make sure they are different for different classes.
My question is how to do it smartly (or automatically) by using like template techniques since manual assignment is error-prone. Any way to get the id is fine, like
class A
{
public:
static const id = ...;
};
or
template<class A>
struct Id
{
enum { value = ... };
};
Easiest way is just a function
int nextId() {
static int rval = 1;
return rval++;
}
class A { public: static const id = nextId(); };
class B { public: static const id = nextId(); };
class C { public: static const id = nextId(); };
That will work so long as you do not need to use the IDs in dynamic initialization at the start of the program.
Edit: if that is not sufficient, the next step up is to do the same thing with static variables in a template. This works across compilation units, but is still dynamic initialization time.
template <typename DummyT = void>
struct CommonCounter
{
public:
static int nextId() {
static int rval = 1;
return rval ++;
}
};
template <typename T>
struct IdFor
{
static int value()
{
static int rval = CommonCounter<>::nextId();
return rval;
}
};
class A { public: static const id = IdFor<A>::get(); };
You could do something like this. This should give the same order on the same compiler. You could also modify how you key things to get a known order and detect problems at initialisation time. Simple implementation, not tested.
#include <typeinfo>
class A {
public:
virtual ~A();
static void register_type(std::type_info const& t);
int id() const;
};
template<class T>
struct DoInitA
{
DoInitA() { A::register_type(typeid(T)); }
};
class B : public A
{
static DoInitA<B> s_a_init;
public:
~B() { }
};
//
// Implementation file.
//
#include <vector>
#include <functional>
namespace {
struct TypeinfoLess {
typedef std::reference_wrapper<const std::type_info> value_type;
bool operator()(value_type const& lhs, value_type const& rhs) const {
return lhs.get().before(rhs.get());
}
};
}
typedef std::vector<std::reference_wrapper<const std::type_info>> TypeVector;
static TypeVector s_types;
static bool s_init_complete = false;
A::~A() { }
void A::register_type(std::type_info const& t)
{
static int s_counter = 0;
if (s_init_complete)
throw std::runtime_error("Late initialisation");
s_types.push_back(std::reference_wrapper<const std::type_info>(t));
}
int A::id() const
{
if (!s_init_complete) {
sort(s_types.begin(), s_types.end(), TypeinfoLess());
s_init_complete = true;
}
for (size_t i = 0; i < s_types.size(); ++i)
if (s_types[i].get() == typeid(*this)) return i;
throw std::runtime_error("Uninitialised type");
}

How to make variable type polymorphism work?

I have a template Node which returns data of type T.
template <class T> Node
{
public:
virtual const T& GetData() = 0;
};
And I want to have derived classes RefNode, and ValueNode that contain Pointers to data, and actual data. So that I can choose whether to work with a copy of data or to work on actual data in a node.
template<class T> class RefNode : public Node<T>
{
public:
RefNode(T *_data) : data(_data) { }
const T& GetData() { return *data; }
protected:
DataType *data;
};
template<class T> class ValueNode : public Node<T>
{
public:
ValueNode(const T&_data) : data(_data) { }
const T& GetData() { return data; }
protected:
T data;
};
I know that templates can't have virtual methods, but I just wanted to illustrate the effect that I wanted to get. The effect that I wanted to get is:
//for class Vector
Vector v, *c;
c = new Vector();
Node<Vector>* node = new RefNode<Vector>(c);
Node<Vector>* node2 = new ValueNode<Vector>(a);
node2->GetData(); //calls ValueNode<Vector>'s GetData();
node->GetData(); //calls RefNode<Vector>'s GetData();
Is there any way in C++ to achieve this kind of behaviour?
EDIT:
I would use GetData() like this:
Vector *vecarr[9];
Node<Vector>* nodes[10];
nodes[0] = new RefNode<Vector>(vecarr[0]);
nodes[1] = new ValueNode<Vector>(Vector(2,3)); //non reference vector
nodes[2] = new RefNode<Vector>(vecarr[1]);
nodes[3] = new RefNode<Vector>(vecarr[2]);
.....
void processPositionNodes(Node<Vector> **nodes, int n)
{
for(int i=0; i< n; i++) //iterate over all nodes
{
Vector vec = nodes[i]->GetData();
//do something with vec
}
}
I want to be able to change the type of data the Node contains, because I want to implement several graph algorithms dealing with different types of data, (Vectors, scalars..)
This code works just fine (there are some minor and unrelevant changes to your version):
#include <iostream>
using namespace std;
template <class T>
class Node
{
public:
virtual const T& GetData() = 0;
};
template<class T>
class RefNode : public Node<T>
{
public:
RefNode(T *_data) : data(_data) { *data = 5; }
const T& GetData() { return *data; }
protected:
T *data;
};
template<class T> class ValueNode : public Node<T>
{
public:
ValueNode(const T&_data) : data(_data) { data = 5; }
const T& GetData() { return data; }
protected:
T data;
};
int main(){
double data;
Node<double>* rn = new RefNode<double>(&data);
Node<double>* rv = new ValueNode<double>(data);
const double& a = rn->GetData();
const double& b = rv->GetData();
cout << a << '\t' << b << endl;
}
However, there are some potential issues with this code: lack of virtual destructor in class Node, lack of copy ctor, dtor, and operator= in class RefNode
As pointed out in the comments, templates can indeed have virtual functions. However this is not going to solve your problem. In fact, you would need those functions to have different return types.
This is a possible template-based solution to your problem, it might not be the most elegant but you (we) can work on this basis
#include <iostream>
using namespace std;
template <typename T, template<typename> class Accessor, template<typename> class Traits>
class Node{
public:
Node() : data(5.){}
typedef typename Traits<T>::type getType;
getType get(){
return static_cast<Accessor<T>*>(this)->implementation();
}
virtual ~Node(){}
protected:
T data;
};
template <typename T>
struct TraitsP{
typedef T* type;
};
template <typename T>
class PointerAccessor : public Node<T, PointerAccessor, TraitsP>{
public:
typename TraitsP<T>::type implementation(){
return &(Node<T, PointerAccessor, TraitsP>::data);
}
};
template <typename T>
struct TraitsD{
typedef T type;
};
template <typename T>
class DirectAccessor : public Node<T, DirectAccessor, TraitsD>{
public:
typename TraitsD<T>::type implementation(){
T ret = Node<T, DirectAccessor, TraitsD>::data;
return ret;
}
};
int main(){
auto np = new PointerAccessor<double>();
double* p = np->get();
cout << *p << endl;
auto np2 = new DirectAccessor<double>();
double d = np2->get();
cout << d << endl;
}
What might seem strange about this solution is PointerAccessor being derived by Node\<..., PointerAccessor, ...>. This is the so called Curiously Recurring Template Pattern (CRTP)

C++ abstract class template

I have the following code:
template <typename T>
class ListBase
{
protected:
int _size;
public:
ListBase() {_size=0;}
virtual ~ListBase() {}
bool isEmpty() {return (_size ==0);}
int getSize() {return _size;}
virtual bool insert(int index, const T &item) = 0;
virtual bool remove(int index) = 0;
virtual bool retrieve(int index, T &item) = 0;
virtual string toString() = 0;
};
My second file defines a subclass:
#define MAXSIZE 50
template <class T>
class ListArray : public ListBase
{//for now to keep things simple use int type only later upgrade to template
private:
T arraydata[MAXSIZE];
public:
bool insert(int index,const T &item)
{
if(index >= MAXSIZE)
return false;//max size reach
if (index<0 || index > getSize() )//index greater than array size?
{
cout<<"Invalid index location to insert"<<endl;
return false;//invalid location
}
for(int i = getSize()-1 ; i >= index;i--)
{//shift to the right
arraydata[i+1]=arraydata[i];
}
arraydata[index] = item;
_size++;
return true;
}
string ListArray::toString()
{
ostringstream ostr;
ostr<<"[";
for(int i = 0; i < _size;i++)
ostr<<arraydata[i]<<' ';
ostr<<"]"<<endl;
return ostr.str();
}
};
My main.cpp:
int main()
{
ListArray<char> myarray;
myarray.insert(0,'g');
myarray.insert(0,'e');
myarray.insert(1,'q');
cout<<myarray.toString();
}
I can't seem to figure out how to use a template with a subclass. When I compile my code, I get the following error:
error C2955: 'ListBase' : use of class template requires template argument list
see reference to class template instantiation 'ListArray' being compiled
You didn't specify the template parameter for ListBase.
template <class T>
class ListArray : public ListBase<T>
---
class ListArray : public ListBase
should be
class ListArray : public ListBase<T>
And you've got a bunch of problems with accessing the base class members. See: Accessing inherited variable from templated parent class.