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);
Related
I want to implement a map, which maps a string to a generic vector.
I want to do this:
std::map<std::string, std::vector<class T> > myMap;
Assuming the proposed myMap had the following inserted into it, it could be used as such:
vector<int> intVec = myMap["ListOfInts"]; // Works because "ListOfInts" maps to a vector<int>
vector<string> stringVec = myMap["ListOfStrings"]; // Works because "ListOfInts" maps to a vector<string>
When I declare the map with the above syntax the compiler has a heart attack.
Can anybody make any suggestions? Or a better associate array option in C++ (suggest non-boost before boost).
Since you know the type you want when you are writing your code, I propose this approach (untested):
// base class for any kind of map
class BaseMap {
public:
virtual ~BaseMap() {}
};
// actual map of vector<T>
template<typename T>
class MapT : public BaseMap, public std::map<std::string, std::vector<T>> {};
class MultiMap {
public:
template<typename T>
std::vector<T>& get(const std::string& key) {
std::unique_ptr<BaseMap>& ptr = maps_[std::type_index(typeid(T))];
if (!ptr) ptr.reset(new MapT<T>());
return ptr->second[key];
}
private:
std::map<std::type_index, std::unique_ptr<BaseMap>> maps_;
}
int main() {
MultiMap map;
std::vector<int>& intVec = map.get<int>("ListOfInts");
std::vector<std::string>& stringVec = map.get<std::string>("ListOfStrings");
}
Maybe this could work for you:
template <typename T>
class MyMap {
std::map<std::string, std::vector<typename T> > map;
public:
/*...*/
};
As mattnewport said boost::variant is one option.
Or to support any types, use boost::any by explicit using any_cast.
Considering boost might be heavy weight, maybe you can reinvent the wheel and simplify it, so that is non boost any more? lol
With C++11, you can use using, it does exactly what you want:
#include <vector>
#include <map>
#include <string>
template<typename T> using mymap = std::map<std::string, std::vector<T>>;
int main()
{
mymap<int> intmap;
mymap<std::string> stringmap;
std::vector<int> intvec = intmap["test"];
std::vector<std::string> stringvec = stringmap["test"];
return 0;
}
Live Demo
Template arguments must be decided compile time. If you want each key of your map to correspond to a vector of a different type, it won't really work. You can get around it with a polymorphic container that returns a void* that you cast to the correct type, but I would suggest trying to find another way to do whatever you want to do with your map first.
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
Hi i have a c++ class with some private members as follows
template <typename V, typename E>
class Vertex
{
public:
Vertex();
~Vertex();
typedef std::pair<int, E> edgVertPair;
typedef std::vector<edgeVertPair> vectEdges;
void setVertexID(int data);
int getVertexID();
void setEdgeVertPair(int vertID, E edge);
edgVertPair getEdgeVertPair();
void setEdgeList(edgeVertPair edgeVert);
vectEdges getEdgeList();
private:
int vertexID;
edgVertPair evp;
vectEdges edgeList;
};
Now i want to create a pair i.e. something like
evp.first="someint";
evp.second="somestring";
and then push this evp into the edgeList i.e. edgeList.push_back(evp);
Now the problem is in the setter function i did something like this:
template<typename V, typename E>
void Vertex<V, E>::setEdgeVertPair(int vertID, E edge){
...populate evp;...
}
now i don't know how to populate the evp pair with vertID, edge.
Use std::make_pair to populate the evp pair.
http://www.cplusplus.com/reference/std/utility/make_pair/
Thanks to all who replied to my question, i figured it out after some search. one way was i removed the typedef's and in my private data section, declared the variables directly as
std::pair<int, E> evp;
std::vector<std::pair<int, E>> edgeList;
and that worked fine.
the other way was i had to prepend the keyword 'typename' before typedef's and it worked.
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.
I would like to put use a string* as a key in an unordered_list. I do not want the hash the pointer itself but the string it points to.
I understand I need to create a struct like this:
struct myhash{
size_t operator()(const string * str){
return hash(*str);
}
}
and send it as a a hasher to the map template, but i am not sure how.
That's basically it. You then provide it as the third template parameter to the unordered_map type (Which I will assume to be the C++0x one). I would generalize it so it's usable in any situation, rather than just string:
struct dereference_hash
{
template <typename T>
std::size_t operator()(const T* pX)
{
return std::hash<T>()(*pX);
}
};
typedef std::unordered_map<std::string*, int, dereference_hash> map_type;