c++ std::map class with generic key - c++

I have a family of classes, and each subclass needs a map but the keys will have different types, although they both will perform the exact same operations with the map. Also the value on both cases will be string.
So far I have code similar to the example below, my goal is to reuse code, by
having a generic key.
Without using any additional libraries besides STL
class A{
public:
/*
* More code
*/
};
class subA1 : public A{
public:
void insertValue(long id, std::string& value){
if(_theMap.find(id) == _theMap.end())
{
_theMap[id] = value;
}
}
private:
std::map<long,std:string> _theMap;
};
class subA2 : public A{
public:
void insertValue(std::string& id, std::string& value){
if(_theMap.find(id) == _theMap.end())
{
_theMap[id] = value;
}
}
private:
std::map<std::string,std:string> _theMap;
};

Simply make superclass A a template, move both _theMap and insertValue() to it, and use the correct template version in subclasses.
template <typename KeyT>
class A{
public:
void insertValue(KeyT id, std::string& value){
if(_theMap.find(id) == _theMap.end())
{
_theMap[id] = value;
}
}
private:
std::map<KeyT, std:string> _theMap;
};
class subA1 : public A<long> {};
class subA2 : public A<std::string> {};

You can merge subA1 and subA2 into a single template class, eg:
class A{
public:
/*
* More code
*/
};
template <typename KeyType>
class subA : public A {
public:
void insertValue(const KeyType &id, const std::string& value) {
if(_theMap.find(id) == _theMap.end()) {
_theMap.insert(std::make_pair(id, value));
}
}
private:
std::map<KeyType, std:string> _theMap;
};
You can then create typedefs as needed:
typedef subA<long> subA1;
typedef subA<std::string> subA2;
Or, if you need actual derived classes:
class subA1 : public subA<long>
{
...
};
class subA2 : public subA<std::string>
{
...
};

How about writing another small base class, say C<T> which is a template typename T and just includes a map<T, string> and your insert function. Then each new subclass of A will also be a subclass of C as well. So your subA1 will be public A, public C<long> etc.

Related

How to: Template class that contains container of it's base class derived objects

I want to establish a template class model that is structured in such a way that there is a base template, which in turn is to be stored in a derived template class as an object in a std::unordered_map.
Each object has a unique key, which can be of different data types (POD, struct, ...).
I don't know how to tell the derived container class to use the type of the key of the passed child class for the key of the unordered_map. Specifically if the objects have been derived from the base class and then are no longer template classes due to specialization.
What I did so far:
** // The base class**
template <typename IDType> class XRObject {
public:
XRObject() : ID_() {
}
XRObject( const IDType& id) :
ID_(id){
}
XRObject(const XRObject& other) : ID_(other.ID_)
{
}
virtual ~XRObject() = default;
IDType getID() const {
return ID_;
}
void setID(const IDType& id) {
ID_= id;
};
private:
IDType ID_;
};
// The derived container class
template <class IDType=long, class T=XRObject> class XRObjectContainer : public XRObject<IDType> {
public:
using ptr_type = typename std::shared_ptr<T>;
using container_type = typename std::unordered_map<**IDType of class T**, ptr_type>;
using iterator = typename container_type::iterator;
using const_iterator = typename container_type::const_iterator;
using sorted_containter_type = typename std::multimap<std::wstring, **IDType of class T**>;
using sorted_iterator = typename sorted_containter_type::const_iterator;
XRObjectContainer() : XRObject<IDType>() {
}
XRObjectContainer(IDType id) {
}
XRObjectContainer(const XRObjectContainer& rhs) : XRObject<IDType>(rhs) {
}
protected:
container_type children_;
sorted_containter_type sortedbyname_;
};
// Concrete class specialisation
class XRUnit : public XRObject {
public:
XRUnit::XRUnit() : XRObjectContainer<long, XRUnit>(), Factor_(0.0, true) {
}
XRUnit::XRUnit(long id, double Factor) : XRObjectContainer<long, XRUnit>(id),
Factor_(Factor) {
}
private:
XRValue<double> Factor_;
};
// The final container class using XRUnit as data members of the internal unordered_map container
class XRUnits : public XRObjectContainer<std::string, XRUnit> {
public:
XRUnits::XRUnits() : XRObjectContainer<std::string, XRUnit>() {
}
XRUnits::XRUnits(const std::string& ID) : XRObjectContainer<std::string, XRUnit>(ID) {
}
};
I don't know how I can get the IDType of class XRUnit automatically determined by the compiler and used in the template class XRUnits as the key type of it's std::unordered_map member? The IDType of the XRObjectType derived class defers from the IDType of the contained unordered_map elements IDType.

Tree Structure with recursive variadic template

I'm trying to make a tree structure to manage data whose structure can change depending on the type.
Here is what I did for the base object
//Type1.. are the types of the leaves having Base as common parent
enum class EnumBase{Type1,Type2,Type3};
class Base {
protected:
EnumBase const _type;
Base(EnumBase typ) : _type(typ){}
public:
virtual ~Base() = default;
Base() = delete;
EnumBase getType() const {return _type;}
};
while this is to create and get different derived
template<class Leaf>
class Controller {
private:
std::shared_ptr<Leaf> _pt;
public:
template<class Derived>
void create() {
_pt = std::make_shared<Derived>();
return;
}
template<class Derived>
Derived & get(){
auto pt = std::dynamic_pointer_cast<Derived>(_pt);
if(!pt){
throw; //bad cast
}
return *pt;
}
};
The second level of the tree goes like:
enum class Type1Types{T1,T2};
class Type1 : public Base {
protected:
Type1Types const _type;
Type1(Type1Types typ) : Base(EnumBase::Type1), _type(typ){}
public:
virtual ~Type1() = default;
Type1() = delete;
Type1Types getType() const {return _type;}
};
class Type2; //...the same with EnumBase::Type2 and Type2Types
class Type3; //...the same with EnumBase::Type3 and Type3Types
with final implementations which may possibly include Controller for another data type:
class T1 : public Type1 {
public:
T1() : Type1(Type1Types::T1) {}
//... data of T1
};
class T2 : public Type1 {
public:
Controller<Type2> objType2;
//... other data for T2
};
The idea behind all this is that I can write:
int main(){
Controller<Type1> obj;
obj.create<T2>();
obj.get<T2>().objType2.create<somethinginType2>();
//...
}
Probably such pattern is overcomplicated (any comment and suggestion is welcomed) but a pattern exists and I believe that it is possible with some template magic and some recursion to write a general templated version of a leaf (Type1, Type2,..) so that I don't have to copy/paste the code and only change the type of the enum for the children (Type1Types) and the type for itself (EnumBase::Type1).
I was thinking of some structure like
template<class Me, class... Parents>
struct MagicStructure{
//some typedef
//my type
}
Any idea?

List inheritance in C++

I'm doing a program that involve a lot of lists of multiple class. I'm pretty sure it has a name but I don't really know how to call it, what I would like to do is to make a common list which contain some functions (like element insertion, getter...) which all lists inherit and can use functions of the common list. So my question is how to do it with an example if possible.
I've made a header code example below.
class CommonList {
public:
// Add some functions
// T here is not a class I've made.
void insere(T element);
T getElement(int id);
protected:
std::map<int,T> m_map;
};
class A {
public: A();
}
class B {
public: B();
}
class ListA : public CommonList {
// Tell the program that element T are ONLY object of class A.
// Like if I would have made this.
/*
public:
void insere(A element);
A getElement(int id);
protected:
std::map<int,A> m_map;
*/
};
class ListB : public CommonList {
// Same for B.
}
I'm pretty sure it has a name but I don't really know how to call it
The word you are looking for is a template class.
And this is how it is being done:
template <typename T>
class CommonList {
public:
void insert(T element){
/* Implement your insert function here */
};
T getElement(int id){
/* Implement your getElement function here */
};
protected:
std::map<int,T> m_map;
};
And then you can simply create any type of that list, for example:
int main(){
CommonList<int> int_list;
my_list.insert(7);
CommonList<double> double_list;
my_list.insert(4.3);
}
You may of course also inherit from this class to and override the functions as you wish.
class A{};
class ListA : public CommonList<A>{
// ...
};
Or as a template
template <typename T>
class ListT : public CommonList<T>{
// ...
};

C++ interface style programming. Need a way out

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

How can be done this automatic?

Is there any way to do this automatically for all derived classes, that i don't have to create function applyPack for all nested classes.
This is piece of my code:
/** every class has registered id with this function */
template<typename T>
uint getID() {
static uint id = registerClass<T>();
return id;
}
class TemplatesPack {
public:
template<typename T>
typename T::Template get();
};
class Object {
public:
virtual void applyPack(TemplatesPack *p) { this->setTemplate(p->get<Object>()); };
};
class Object2: public Object {
public:
void applyPack(TemplatesPack *p) { this->setTemplate(p->get<Object2>()); };
};
class Object3: public Object {
public:
void applyPack(TemplatesPack *p) { this->setTemplate(p->get<Object3>()); };
};
class Object4: public Object2 {
public:
void applyPack(TemplatesPack *p) { this->setTemplate(p->get<Object4>()); };
};
I've read something about type traits but i don't want to have class Object templated. Can be this done with c++ and templating some functions in class TemplatesPack or with c++0x? s
Edit:
changed the answer to make the Object untouched.
template<class T>
class Base<T> : public Object
{
public:
virtual void applyPack(TemplatePack *p) { this->setTemplate(p->get<T>()); };
};
class Object2 : public Base<Object2>
{
// ...
};
Edit: for the case of Object4, maybe the following will help:
template<class S, class D>
class Base<S, D> : public S
{
public:
virtual void applyPack(TemplatePack *p) { this->setTemplate(p->get<D>()); };
};
class Object2 : public Base<Object, Object2> { /* ... */ };
class Object3 : public Base<Object, Object3> { /* ... */ };
class Object4 : public Base<Object2, Object4> { /* ... */ };
You could use virtual inheritance and the dominance rule, if you don't want to templatize Base
template<typename Derived, typename Base = void>
struct applyer : virtual applyer<Base, typename Base::base_type> {
virtual void applyPack(TemplatesPack *p) {
dynamic_cast<Derived*>(this)->setTemplate(p->get<Derived>());
};
typedef Base base_type;
};
template<typename Derived>
struct applyer<Derived, void> {
virtual void applyPack(TemplatesPack *p) {
dynamic_cast<Derived*>(this)->setTemplate(p->get<Derived>());
};
};
Now you can do it as follows
class Object : virtual public applyer<Object> {
};
class Object2: public Object, virtual public applyer<Object2, Object> {
};
class Object3: public Object, virtual public applyer<Object3, Object> {
};
The second argument respectively is the direct base class, which can be omitted if there is none. For instance if you derive from Object3, you need to do that as follows
class Object3_1: public Object3, virtual public applyer<Object3_1, Object3> {
};