Problems with map as array - c++

Good day!
I'm making nondeterministic finite automata with c++. I want to make a transition table. As you know, it should return a set of states. For example, table[state][symbol] should return {q0,q1, etc..}.
I'm using std::map and std::set for this. I found this useful example : how to use stl::map as two dimension array
So, i wrote some code:
std::map <set<state>, std::map<state,char> > transitionTable;
But when i'm trying to acsess the table like
set<state> result = transitionTable[oldState][symbol];
I get an error:
C:\NFA2\main.cpp||In function 'std::set<state, std::less<state>, std::allocator<state> > delta(state, char)':|
C:\NFA2\main.cpp|17|error: no match for 'operator[]' in 'transitionTable[oldState]'|
Can you help me?
Thanks in advance.

From your description it sounds like you want (typedefs for readability):
typedef std::set<state> StateSet;
typedef std::map<char, StateSet> SymbolToStatesMap;
typedef std::map<state, SymbolToStatesMap> TransitionTable;
TransitionTable transitionTable;
Keep in mind that the first type argument to map is the key type, so if you want an access like this:
A a;
B b;
C c = myMap[a][b];
the map type should be:
std::map<A, std::map<B, C> >
To actually be able to use custom types as a key in a map, they have to implement operator<:
class state {
// ...
public:
bool operator<(const state& rhs) const {
// ... custom stuff here
}
Alternatively you can pass a custom comparer to map.

I assume that oldState is a set. If that is the case, transitionTable[oldState] returns you a map and transitionTable[oldState][symbol] is invalid if symbol is not a set and hence error.

std::map <set<state>, std::map<state,char> > transitionTable;
You have a set as key in the map, not a state.

What are the types of oldState and symbol?
From what I understand of your problem, I suspect that the type
of transitionTable should be:
std::map<std::set<state>, std::map<char,std::set<state> > transitionTable;
At least, this would give the mapping: (set_of_states, char) ->
set_of_states, if used as in your example, where oldState is
a set of states, and symbol is a char.

Related

custom comparison method for c++ map based on key and value

I searched a lot but I didnt find the answer I want.
I need to sort c++ map based on keys and values.
something like this method :
bool mycomp(mii::iterator a, mii::iterator b) {
if (a->second > b->second)
return true;
else if (a->second < b->second)
return false;
else
return a->first > a->second;
}
and use it something like that
sort(m.begin() , m.end(), mycomp);
where m is :
map<int,int> m;
can I do such thing ? if yes, what should be the correct syntax.
When you define the std::map you can provide a Compare function as a template parameter. See the reference for more details.
However, I believe this is only for key sorting. Key-value sorting is not inherit to the map structure (i.e. what happens if the value changes?)

unordered_map of different custom types

Suppose if I have these two enums:
enum Type
{
Type1,
Type2
};
enum Location
{
Location1,
Location2,
Location3
};
Now I would like to have a container that I can reference like container[Type1][Location1] = 5;
I don't need the elements to be sorted but I need to be able to have duplicates like container[Type1] can be either Location1 or Location2 etc.
I was thinking to use an unordered_multimap<pair<Type, Location>, unsigned int>> which kind of provides what I want, but does not allow me to access the elements as described (or at least I don't know how to do that)
What suggestions do you have?
I believe you're looking for nested maps:
std::unordered_map<Type, std::unordered_map<Location, unsigned int>>

Changing std::pair type affects hashmap

Initially I had code that looked like this:
std::map< std::pair<int,int>, std::vector<Class0*> > aMap;
It worked. Now I have code that looks like this:
std::map< std::pair<Vec3f, Vec3f>, std::vector<Class0*> > aMap;
It no longer maps correctly (compiles fine). Why? And how can I fix that?
EDIT: After popular demand here is the comparison code for a 3D vector (3 floats):
class Vec3f {
...
bool operator () ( const Vector3f& v0, const Vector3f& v1 ) const {
return std::tie(v0[0], v0[1], v0[2]) < std::tie(v1[0], v1[1], v1[2]);
} ...
from this question Overloading operator for set. The above comparison works fine for a set, but apparently not for a pair. Why?
The key to the map is a pair. The comparison of pair is lexicographic: it first compares the first elements of both pairs. If both appears to be equal, it also compares the second elements. So you need a proper comparison for both Class1 and Class.
Additional considerations:
On each class of the pair, the map comparator less-than must comply with some constraints:
it must establish a stritct weak oredering between all the elements.
(! k1<k2) && (! k2<k1) is equivalent to k1==k2
k1<k2 && k2<k3 implies that k1<k3
If any of this property is broken, the strict order is not guaranteed and the mapping may fail.

Registry of different types of data

I want to keep some kind of container where a type maps to one value of the type. So essentially what I want is a std::map<std::typeindex, T> where T depends on the type I index it with. std::map doesn't look like a nice way of doing this because the types are rigid. What is the simplest solution I can use for doing this?
If you map to a type-erased container like boost::any, you can at least recover the type if you know what it is:
std::map<std::typeindex, boost::any> m;
m[typeid(Foo)] = Foo(1, true, 'x');
Foo & x = boost::any_cast<Foo&>(m[typeid(Foo)]);
You could use a shared_ptr<void>:
std::map<std::typeindex, std::shared_ptr<void>> m;
m[typeid(T)] = std::make_shared<T>(...);
auto pT = std::static_pointer_cast<T>(m[typeid(T)]); // pT is std::shared_ptr<T>
Or course you would add some wrapper to ensure that the two Ts per line match and you don't accidentially access an empty shared_ptr<void>.

Circular dependency in MRU construct using std::map and std::list

I have a map (std::map<key_t, val_t>) and I want to keep track of the keys that are used in the order of most recent to least recent.
This is what I tried, but I get stuck on the declaration with a circular-dependency:
typedef ... key_t;
typedef struct {
...
mru_list_t::iterator mru_it;
} val_t;
typedef std::map<key_t, val_t> foo_map_t;
typedef std::list<foo_map_t::iterator> mru_list_t;
The update routine seems straight-forward enough:
foo_map_t foo_map;
mru_list_t mru_list;
void use(const key_t& key) {
// get the entry corresponding to the key
std::pair<foo_map_t::iterator, bool> r;
r = foo_map.insert(std::make_pair(key, val_t()));
foo_map_t::iterator map_it = r.first;
// the corresponding value
val_t *val = &(*map_it).second;
// did it already exist?
if (!r.second) {
// remove from the mru list
mru_list.erase(val->mru_it);
}
// push to the front of the list
mru_list.push_front(map_it);
val->mru_it = mru_list.begin();
}
How should I deal with this? (The circular dependency)
I know that I could forward declare and use a pointer instead:
typedef struct _key_t key_t;
typedef struct _val_t val_t;
typedef std::list<std::pair<key_t, val_t> *> mru_list_t;
But this seems to rely on an undocumented feature.
EDIT: Or, do I need to realize that this can't be done? (And go with the undocumented feature, roll my own linked-list, or otherwise replace parts with some other non-stl container?)
Depending on what kind of things you are using as keys, and because of the fact that you are using a single-value map, you could try just storing a key_t in your list, instead of storing an iterator into the std::map. Because the map only has a single value per key, you still have unique access to the element, and you get rid of this horrible circular dependency problem.
The code would look something like:
typedef std::list<key_t> mru_list_t;
for the type of the list, and at the end of your use function, you would need to change:
mru_list.push_front(map_it);
to
mru_list.push_front(map_it->first);
I suggest that you take a look at Boost Multi Index which is built to allow several indexes on the same piece of data (and can therefore match several orders).
More specifically, there is an example of MRU already, although you may not want to look at it right now, and experiment with the library by yourself.
The main idea of Boost Multi-Index is that instead of having pointers to elements and multiple inter-related structures that may fall out of sync, you instead inscribe each element in a container cell designed to be hooked on the multiple indexes.
In the example of a MRU, you could for example implement the linked-list yourself by inscribing each "value" into a struct V { value_t value; V* next; }, for example.