container of template class in c++ - c++

I have a template, which may be used with different stl map (map<int, int>, map<int, char>, etc.), as follows.
template <typename Map> struct TriMaps
{
Map& next;
Map& prev;
Map& curr;
};
so, TriMaps<init, int> intTriMaps; TriMaps<int, char> charTriMaps;
Then, is it possible to have a container of the above TriMaps, in different type? e.g.
vector <TriMaps> vecMaps;
which contain intTriMaps and charTriMaps? Usually container requires the same type. But I really need a container for my case. No boost or third library available.

First determine and finalize what this class template TriMaps is expected to do. In C++, you must initialize a reference to something. You probably need a non-reference type (or a pointer type). Consider:
template <typename Map>
struct TriMaps
{
Map next;
Map prev;
Map curr;
};
Usage:
TriMaps<int> IntMaps;
vector<TriMaps<int>> iv;
If you need two template type argument, you can do this way:
template <typename MapType1, typename MapType2>
struct TriMaps
{
MapType1 a;
Maptype2 b;
};
Usage:
TriMaps<int, float> IntMaps;
vector<TriMaps<int, float>> iv;
EDIT:
Carefully understand that following simple class will not compile.
class TriMap
{
int & ref_int;
};
One approach is to refer a global variable (just to make it compile), or take an int& via a constructor.
// Approach 1
int global;
class TriMap
{
int & ref_int;
public:
TriMap() : ref_int(global) {}
};
// Approach 2
class TriMap
{
int & ref_int;
public:
TriMap(int & outer) : ref_int(outer) {}
};

You can't have a std::vector of different type
but if you can have base class
struct TriMapBase { virtual ~TriMapBase() = default; };
template <typename Map> struct TriMaps : TriMapBase { /* Your implementation */ };
Then you may have:
TriMapBase<std::map<int, int>> mapint;
TriMapBase<std::map<int, char>> mapchar;
std::vector<TriMapBase*> v = {&mapint, &mapchar};
but you have to use virtual functions
or dynamic_cast to retrieve the correct type afterward...
or use

Related

Using the allocator for a structure fields of different types

I have a custom allocator which instances share a memory buffer of type TrivialSpace:
class TrivialSpace
{
public:
uint8_t * Allocate(std::size_t memory_size)
{
...
return ptr_to_mem;
}
...
};
template <class T>
class TrivialAllocator
{
public:
using value_type = T;
TrivialAllocator(TrivialSpace & space) : m_space(space)
{
}
template <class Q>
TrivialAllocator(const TrivialAllocator<Q> & other) : m_space(other.m_space)
{
}
T * allocate(std::size_t n)
{
return reinterpret_cast<T*>(m_space.Allocate(n * sizeof(T)));
}
void deallocate(T* p, std::size_t n)
{
}
private:
TrivialSpace & m_space;
template <class Q>
friend class TestAllocator;
};
and a structure containing std::string and std::vector:
using String = std::basic_string<char, std::char_traits<char>, TrivialAllocator<char>>;
template <class T>
using Vector = std::vector<T, TrivialAllocator<T>>;
struct A
{
String a;
Vector<int> b;
Vector<String> c;
};
1) what is the right way to create an instance of A structure my TrivialAllocator?
2) And how to make the code work with both TrivialAllocator and std::allocator? When the field types are defined as above or as follows (depending on some #ifdef probably):
using String = std::string;
template <class T>
using Vector = std::vector<T>;
My idea was to pass the instance of Allocator to the structure constructor, but it is not clear what specialization of Allocator should I pass - Allocator<char>, Allocator<int> or something else.
I would specifically take 3 allocators (for example, if you used a polymorphic allocator, you might want a specific one for each object).
You could also have an overloaded constructor that takes one allocator and constructs the other three from it (Only if each allocator is rebound from the other 2, which in this case or with a polymorphic allocator they are)
A(Allocator<char> a_alloc, Allocator<int> b_alloc, Allocator<String> c_alloc) : a(a_alloc), b(b_alloc), c(c_alloc) {}
template<class Alloc,
std::enable_if_t<
std::is_same_v<std::allocator_traits<Alloc>::template rebind_alloc<char>, Allocator<char>> &&
// Next 2 maybe redundant based on what you are doing
std::is_same_v<std::allocator_traits<Alloc>::template rebind_alloc<int>, Allocator<int>> &&
std::is_same_v<std::allocator_traits<Alloc>::template rebind_alloc<String>, Allocator<String>>,
int> = 0>
A(Alloc alloc) : A(Allocator<char>(alloc), Allocator<int>(alloc), Allocator<String>(alloc)) {}
Or you could pass the issue to the constructor of the class and move from a string and two vectors (Or leave it as an aggregate and initialize with allocators where the type is used)

Multidimensional map template accessed and assigned inside of class method

I was wondering if this was a valid way to assign a multidimensional map inside of a class method and if not how would I go about doing this.
template<typename T>
std::map<std::string, std::map<std::string, T>> MT;
template<typename T>
void MonsterTemplate(std::string name, std::string node, template T v) {
MT[name][node] = v;
}
Edit1: I compiled and it gave me many errors but I will just give a portion of the 1st.
error C3376: 'MonsterType::MT': only static data member templates are allowed
Edit2:
I tried creating a struct
template<typename T>
struct Wrapper
{
typedef std::map<std::string, std::map<std::string, T>> MT;
};
I then added this inside the class
template<typename T>
Wrapper<T>::MT mt;
template<typename T>
void MonsterTemplate(std::string name, std::string node, template T v) {
mt[name][node] = v;
}
Then got this error amongst many others.
warning C4346: 'MT': dependent name is not a type
The struct works outside the class without being multidimensional map, but I am unsure how to access it as multidimensional map.. just trying different things.
The idea is I want to store data of several objects data and index them by name, node and value.
Edit3:
So this is what I went with, and haven't gotten an error (just yet :p)
std::map<std::string, std::map<std::string, int>> MT;
void MonsterTemplate(std::string name, std::string node, int v) {
MT[name][node] = v;
}
Just updating this for anyone looking for something similar
So I figured out how to construct this.
template<typename T>
struct Test
{
std::map<std::string, std::map<std::string, std::map<size_t, std::map<std::string, T>>>> testmap;
void MonsterTemplate(std::string creatureName, std::string name, std::string node, T v) {
size_t i = testmap[creatureName][name].size();
testmap[creatureName][name][i][node] = v;
}
};
Test<std::string> str;
Since I needed various data types for T the structure worked much better than trying to find a way to assign a template to a static class, I am only using std::string as an example.
This can then be used inside of the class's method since str has a global scope.
str.MonsterTemplate(creatureName, name, node, value);

c++: can i process std::_Container_base without knowing if it is a map or a vector?

guess I have a
class C1 : public B { /*...*/ };
class C2 : public B { /*...*/ };
std::map<std::string, C1> myMap;
std::vector<C2> myVector;
Is there a way (and what would be the syntax) to call a function foo that…
just needs to process the functionalities of B
just needs to process them on all elements of map and vector without caring how they are organized?
std::vector and std::map are both std::_Container_base's but i have no clue how to write the syntax for (pseudocode):
void foo(std::_Container_base-of-Bs)
EDIT: it's _Container_base, not _Tee
The C++ way is to use templates and iterators.
template <typename ForwardIterator>
void process_bs(ForwardIterator first, ForwardIterator last) {
std::for_each(first, last, [](B& b) {
// do something to b here
});
}
For vector, list, deque and set, you can trivially call this using begin and end:
process_bs(v.begin(), v.end());
For map, the element type is pair<const Key, Value>, so you have to adapt the iterators. You can use this with Boost.Range, for example:
#include <boost/range/adaptor/map.hpp>
auto values = m | boost::adaptors::map_values;
process_bs(values.begin(), values.end());
EDIT: The below is a survey on the workarounds, whereas the actual question is not answered therein. So here is the answer: I don't know whether one can process std::_Container_base without knowing if it is a map or a vector.
I couldn't find anything reasonable on the web regarding std::_Container_base, and particularly no C++ standard things, so I would guess it stems from a specific compiler implementation.
vector and map are completely different storage schemes. I suggest you to not use them generically in the same context. That is, from the first you could write a function template
template<typename T> foo(T&& t) { /* takes a vector and a map */ }
but at least when you access operator[], they'll behave differently. That would be unintuitive and error-prone.
However, this doesn't mean you cannot combine the two approaches -- and abstract on size(), operator[](int) and possibly other things like some insertion mechanism.
For example, in some recent code of mine, I have vector-storage scheme (which uses std::vector under the hood), as well as a piecewise constant vector (which uses a std::map). If you want to do this, you can derive those two from a common base class
template<typename T>
struct ContainerBase
{
virtual int size() const = 0;
virtual T operator[](int) const = 0;
virtual void insert(int, T) = 0; //if required
};
and then set up the required functionality in the derived classes Vector and Map.
template<typename T>
struct Vector
{
virtual T operator[](int i) const { return _v[i]; }
virtual T size() const { return _v.size(); }
// ... insert and so on
std::vector<T> _v;
};
template<typename T>
struct Map
{
virtual T operator[](int i) const
{
return *std::lower_bound(i); //add further checks if nothing is found
}
virtual T size() const { return _v.rbegin()->first; // return highest index }
// ... insert and so on
std::map<int, T> _v;
};
The Map implementation is just a sketch. You should choose some reasonable behaviour for it.
With this, it is easy to set up a function foo(ContainerBase&) which works for both Vector and Map.
To use transparently B subclasses into the foo function, you can do this way:
#include <iostream>
#include <map>
#include <vector>
#include <string>
#include <utility>
struct B{
int b_member;
};
class C1 : public B { /*...*/ };
class C2 : public B { /*...*/ };
std::map<std::string, C1> myMap;
std::vector<C2> myVector;
// all the magic is into get_B specializations
template<typename E, typename std::enable_if<std::is_base_of<B, E>::value>::type* a = nullptr>
B& get_B(E& elem)
{
return elem;
}
template<typename E, typename std::enable_if<std::is_base_of<B, typename E::second_type>::value>::type* a = nullptr>
B& get_B(E& elem)
{
return elem.second;
}
// foo can call get_B to hide implementation details of the container
template<typename T>
void foo( T& container)
{
for(auto& elem : container)
{
std::cout << get_B(elem).b_member << '\n';
}
}
int main()
{
myVector.resize(10);
myMap["one"] = {};
foo(myMap);
foo(myVector);
}
Thanks to SFINAE, foo uses the correct specialization of get_B to get a reference to the B subclass you want to process.

Avoiding code repetition in C++ (partial) template specialization

I have a class Vector which represents a mathematical vector of a given template class. I want to be able to save the vectors in two different ways:
template <class T>
class Vector
{
private:
T* elements;
};
and
template <class T, unsigned int D>
class Vector
{
private:
T elements[D];
};
In the first example I allocate and free the array with new and delete in constructor and destructor.
Now since I don't want to write all the methods twice for both classes, and since it wouldn't even compile this way because I have two classes with the same name but different template arguments, I would like to combine both classes into one class like so:
template <class T, int D = -1>
class Vector
{
public:
Vector<T, D> add(const Vector<T, D>& add) const;
private:
T elements[D];
};
template <class T>
class Vector<T, -1>
{
public:
Vector<T, D> add(const Vector<T, D>& add) const;
private:
T* elements;
};
So the second part is just a partial template specialization of the first one. If no dimensions are given the dynamically allocated option should be used (default argument for D). As an example I added a function to calculate the sum of two vectors.
Now my problem is that I have to give two implementations for what is logically just one function. Whenever I access the elements array it's exactly the same syntax in the dynamic and in the static Vector class. Can I somehow combine both implementations into just one implementation of the add function (and likewise of all similar functions)?
If I cannot solve the problem this way, do you have other ideas of how to create the Vector class with both dynamic and static memory allocation?
I'd go for a policy-based design, similar to the way how std::vector handles allocation.
In your case it means:
Define a class which stores the vector elements but only provides a minimal interface. (Policy)
Define your vector interface independent of the way the elements are stored in the policy. It accesses the elements in a way independent of that implementation. The policy class should be added as a template type parameter (which can have a default value), so the user of your vector class can choose which policy to use. Inherit from the policy class or add a member of its type (privately if you don't want to expose the policy interface in the public interface).
Example (here with aggregation instead of inheritance):
// The policy default implementation:
template <class T, int D>
class VectorStorage
{
T elements[D];
public:
T& operator[](int x) {
return elements[x];
}
const T& operator[](int x) const {
return elements[x];
}
};
class VectorStorage<T, -1>
{
T* elements; // (for allocation, see below)
public:
T& operator[](int x) {
return elements[x];
}
const T& operator[](int x) const {
return elements[x];
}
};
// The vector implementation, independent of the storage,
// but defaulting to the one above:
template <class T, int D = -1, class Storage = VectorStorage<T,D>>
class Vector
{
Storage storage;
public:
Vector<T, D> add(const Vector<T, D>& add) const {
// Access your elements using "storage[x]"
}
};
Note that you need a suitable constructor for your policy class (as in the case of the dynamic storage type, you need the size during construction). Provide a unique constructor interface to all of your specializations, not only for the one which need it; and call the constructor in the vector's constructor appropriately:
// within class VectorStorage<T,-1>:
VectorStorage(int size) : elements(new T[size]) {}
~VectorStorage() { delete[] elements; }
// within class VectorStorage<T,D>:
VectorStorage(int /* ignored */) {}
// within class Vector:
Vector(int size) : storage(size) {}
Alternatively, to support client code like Vector<int,5> myVector; (i.e. default constructor on the static size version), provide a default constructor which is only allowed to be called for the static size version:
Vector() : storage(D) {
static_assert(D != -1, "The default constructor is only allowed for the static-sized version of Vector.");
}
Now a user can even use Vector with std::vector as the storage back-end: Vector<int, -1, std::vector<int>> or Vector<int, 5, std::vector<int>>. Or even Vector<int, 5, std::array<int,5>>.
I would do something like the following, i.e specialize only the data part:
template <class T, int D = -1>
class VectorData
{
public:
int size() const { return D; }
protected:
T elements[D];
};
template <class T>
class VectorData<T, -1>
{
public:
explicit VectorData(int size) : elements(size) {}
int size() const { return elements.size(); }
protected:
std::vector<T> elements;
};
template <class T, int D = -1>
class Vector : protected VectorData<T, D>
{
public:
using VectorData<T, D>::VectorData;
Vector add(const Vector& add) const
{
Vector res(*this);
for (int i = 0; i != this->size(); ++i) {
res.elements[i] += add.elements[i];
}
return res;
}
};

Switch template type

I want to make some storage for my game. Now the code looks like:
class WorldSettings
{
private:
std::map<std::string, int> mIntegerStorage;
std::map<std::string, float> mFloatStorage;
std::map<std::string, std::string> mStringStorage;
public:
template <typename T>
T Get(const std::string &key) const
{
// [?]
}
};
So, I have a few associative containers which stores the exact type of data. Now I want to add into settings some value: settings.Push<int>("WorldSize", 1000); and get it: settings.Get<int>("WorldSize");. But how to switch need map due to passed type into template?
Or, maybe, you know a better way, thanks.
If your compiler supports this1, you can use template function specialisations:
class WorldSettings
{
private:
std::map<std::string, int> mIntegerStorage;
std::map<std::string, float> mFloatStorage;
std::map<std::string, std::string> mStringStorage;
public:
template <typename T>
T Get(const std::string &key); // purposely left undefined
};
...
template<>
int WorldSettings::Get<int>(const std::string& key) {
return mIntegerStorage[key];
}
template<>
float WorldSettings::Get<float>(const std::string& key) {
return mFloatStorage[key];
}
// etc
Notice that the methods are not const because map<>::operator[] is not const.
Also, if someone tries to use the template with a type other than one you have provided a specialisation for, they will get linker errors, so your code won't misbehave or anything. Which is optimal.
1 If not, see #gwiazdorrr's answer
First of all, since prior to C++11 you can't specialise functions, your member functions must differ in signature - return type does not count. From my experience on some compilers you can do without it, but as usual - you should keep your code as close to standard as possible.
That said you can add a dummy paramater that won't affect performance and the way you call function:
public:
template <typename T>
T Get(const std::string &key) const
{
return GetInner(key, (T*)0);
}
private:
int GetInner(const std::string& key, int*) const
{
// return something from mIntegerStorage
}
float GetInner(const std::string& key, float*) const
{
// return something from mFloatStorage
}
And so on. You get the idea.
Seth's answer is ideal, but if you don't have access to a C++11 compiler, then you can use template class specialization and do this instead. It's much more verbose, but keeps the same functionality.
class WorldSettings
{
template<class T>
struct Selector;
template<class T>
friend struct Selector;
private:
std::map<std::string, int> mIntegerStorage;
std::map<std::string, float> mFloatStorage;
std::map<std::string, std::string> mStringStorage;
public:
template <typename T>
T Get(const std::string &key)
{
return Selector<T>::Get(*this)[key];
}
};
template<>
struct WorldSettings::Selector<int>
{
static std::map<std::string, int> & Get(WorldSettings &settings)
{
return settings.mIntegerStorage;
}
};
template<>
struct WorldSettings::Selector<float>
{
static std::map<std::string, float> & Get(WorldSettings &settings)
{
return settings.mFloatStorage;
}
};
// etc.
In C++03 I would recommend the use of ‘boost::any‘ in the type of the container, and the. You need a single accessor:
std::map<std::string,boost::any> storage;
template <typename T> getValue( std::string const & key ) {
return boost::any_cast<T>( storage[key] );
}
This is a rough sketch, as a member function It would be const, and it should use ‘map::find‘ not to modify the container when searching, it should deal with invalid joeys, and probably remap the boost exceptions into your own application exceptions.