If I have a std::multimap<int, std::map<int, MyClass>> myMultimap how to I insert a class object MyClassA into the map with value 1 at multimap value 2?
It looks like I can do myMultimap.at(2).insert(std::pair<1,MyClassA>); in c++11 but I am using c++98 due to a library regression/incomparability out of my control.
I've also tried
myMultimap[2].insert(
std::make_pair(
myMultimap[2].end(),
myClassA
)
);
which gives: error: no match for ‘operator[]’ (operand types are ‘std::multimap<int, std::map<int, ns_namespace::MyClassType> >’ and ‘int’)| for both of the [...]'s.
I don't want to do something like myMultimap.insert(std::make_pair(2,std::make_pair(1,MyClassA)))
because if I understand correctly, this would make a new map in the multimap rather than assigning the class object to the existing map within the multimap.
It is a two stage process:
Locate the position in the outer map where you want to do something to the inber map. If necessary, insert a new element.
Update the inner map withthe appropriatevalue.
I don't know why the outer map us a multimap (they are rarely useful) so the exampke just uses the first entry:
auto it = mymultimap.lower_bound(2);
if (it == mymultimap.end() || it->first != 2) {
it = mymultimap.insert(
std::make_pair(2, std::map<int, MyClass>())).first;
}
(*it)[1] = MyClassA;
(typed on a mobile device: there are probably typos but the overall approach should work).
Related
I am trying to create a map, something like: [{11,"Jitendra", 15.5}, {12, "Pranay", 15.5}], where the data between first curly brackets becomes the key and between the second curly brackets becomes values. Whatever technique I am trying it results in error.
Please let me know how I can declare an STL map, insert and manipulate values?
Compound variables are usable as keys for a map as long as they are comparable with operator< (see std::less). The simplest case is using a std::pair:
std::map<std::pair<int, std::string>, int> mymap; // key: int, string; value: int
You can extend the concept with an arbitrary number of key elements by using std::tuple as introduced in C++11.
Both pairs and tuples bring their own comparator overloads (see e.g. for tuple here), so no further work is needed on your side if your tuple elements are comparable by-themselves and are happy with an ordering that gives precedence on the first, then the second, and so on, element of the pair/tuple. Use std::make_pair() or std::make_tuple() to conveniently create them. However, it also works like this (C++17):
std::map<std::tuple<int, int>, std::tuple<int, int>> foo;
// insert
foo[{1,2}] = {3,4};
// access
auto [v1, v2] = foo[{1,2}];
std::cout << v1 << ", " << v2 << std::endl;
To be most flexible, you can extend it even further by using a struct and providing a comparator for the map to order its elements. You can also do this if your compiler lives behind the moon and does not support C++11.
I'm trying to retrieve a value from a boost::multi_index_container, using a unique numerical id index. I've never used boost::multi_index_container before so I have some trouble understanding how they work. They seem to work a bit like a database, all I want to do is to retrieve an item by specifying the id. Any help would be greatly appreciated.
This is the datatype:
typedef boost::multi_index_container<
// Multi index container holds pointers to the subnets.
Subnet6Ptr,
// The following holds all indexes.
boost::multi_index::indexed_by<
// First is the random access index allowing for accessing
// objects just like we'd do with a vector.
boost::multi_index::random_access<
boost::multi_index::tag<SubnetRandomAccessIndexTag>
>,
// Second index allows for searching using subnet identifier.
boost::multi_index::ordered_unique<
boost::multi_index::tag<SubnetSubnetIdIndexTag>,
boost::multi_index::const_mem_fun<Subnet, SubnetID, &Subnet::getID>
>,
// Third index allows for searching using an output from toText function.
boost::multi_index::ordered_unique<
boost::multi_index::tag<SubnetPrefixIndexTag>,
boost::multi_index::const_mem_fun<Subnet, std::string, &Subnet::toText>
>
>
> Subnet6Collection;
The Subnet6Collection object is created when a dhcpv6-server (KEA) loads its config file. This file contains an optional numerical id value for each subnet, SubnetID in the datatype.
I would like to retrieve a Subnet6Ptr by specifying SubnetID.
Yes, Mutli-index can be a difficult beast to work with. As I wrote in a different answer, "Boost.Multi-index offers an extremely customisable interface, at the cost of offering an extremely complex interface."
Basically, when you want to access the contents of the container, you do it through one of its indices. You therefore start by obtaining a reference to the index which you want to use (the on tagged SubnetSubnetIdIndexTag in your case), and then treat that index pretty much like a container. Which container that is depends on the index's type. For an oredered unique index (as in your case), that would be somewhat like std::map (but with iterators pointing to values only), or like std::set with a transparent comparator which only compares IDs.
Here's what it looks like in code:
Subnet6Collection coll = something();
SubnetID idToLookFor = something2();
auto& indexById = coll.index<SubnetSubnetIdIndexTag>();
auto it = index.find(idToLookFor);
if (it != index.end()) {
Subnet6Ptr p = *it;
} else {
// No such ID found
}
Thanks for answering.
I tried the following (SubnetID is just uint32_t so I used 10 for test):
SubnetID id = 10;
Subnet6Collection coll;
auto& indexById = coll.index<SubnetSubnetIdIndexTag>();
auto it = index.find(id);
if (it != index.end()) {
Subnet6Ptr p = *it;
} else {
// No such ID found
}
but it does not compile:
Opt18_lease_select.cc:38:24: error: invalid use of ‘struct boost::multi_index::multi_index_container, boost::multi_index::indexed_by >, boost::multi_index::ordered_unique, boost::multi_index::const_mem_fun >, boost::multi_index::ordered_unique, boost::multi_index::const_mem_fun, &isc::dhcp::Subnet::toText> > > >::index’
auto& indexById = coll.index<SubnetSubnetIdIndexTag>();
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Opt18_lease_select.cc:39:17: error: overloaded function with no contextual type information
auto it = index.find(id);
^~~~
Opt18_lease_select.cc:40:17: error: overloaded function with no contextual type information
if (it != index.end()) {
^~~
Seems like index() find(), end() can't be used this way, or maybe I'm just missing some header file?
I'm trying to make my code 1 line shorter, a noble cause. I have this unordered map
std::unordered_map<std::string, int> um;
and I want to assign the integer to a variable on the same line where I emplace a pair into the unordered map like so
int i_want_132_here = um.emplace("hi", 132).first.???;
problem is, I have no idea what to do with [return value of unordered_map::emplace].first
In the debugger I can see that "first" contains ("hi", 132) but how do I access those values?
emplace returns a pair<iterator, bool>.
So you should do:
int i_want_132_here = (*um.emplace("hi", 132).first).second;
alternative syntax:
int i_want_132_here = um.emplace("hi", 132).first->second;
In general I prefer (*it) form instead of it->.
I have a vector of pairs, which is empty at the beginning. I implemented a custom insert and remove method, and I would also like to be able to assign NULL to certain elements, but I can't because it's not a pointer to pair.
If I try to illustrate it more specifically - given a vector V
std::vector< std::pair<A,B> > V;
neither
V.assign(number,NULL);
nor
V[n]=NULL;
would work.
I need to do this to check if there already is an element saved in a certain slot. Is there anywork around or should I just create another vector of booleans to save wheter a certian slot is full or not?
NOTE: I know any kind of map would solve it elegantly, but it has to be a vector.
I think solution with map would be optimal in your case:
std::map<int, std::pair<A, B> > M;
Then you can do
M.erase(M.find(number))
To NULL-ify to the element.
If I had to do it I would do something like
vector< pair< pair<A,B> ,int > >V , V[i].second can be 0 or 1 depending whether the element
pair has to be NULL or not.This if if you want to mark the pair NULL but still keep it for refernece.Otherwise use map as Alex1985 said.
I advise you to look at boost::optional
boost::optional< std::vector< std::pair<A,B> > > V;
if (V) {
// V was initialized
} else {
// wasn't initialized
}
documentation examples: http://www.boost.org/doc/libs/1_54_0/libs/optional/doc/html/boost_optional/examples.html
Use shared_ptr as the second type in the pair.
std::vector< std::pair<A,std::shared_ptr<B> > > V;
V.assign(number, std::shared_ptr<B>());
V[n] = std::shared_ptr<B>();
V[n] = std::shared_ptr<B>(new B());
if (V[n].get() == NULL) { /* process empty here */ }
The shared_ptr class was introduced to C++ in TR1, and is part of the C++11 specification. It works well with standard containers because it
Assume I have a nested map of type pointer. Then is there a single line statement to insert into the nested map,
map<int, map<int, int> >* nestedMap;
Currently I am doing this in 2 steps. First creating innermap and then insert into outer map as below,
nestedMap->insert(make_pair(int, map<int, int>)(int, innermap));
If the map is not pointer type, then i can insert easily like this,
nestedMap[int][int] = int;
Is there any simple ways for inserting into nested map of type pointer ?
thanks
Prabu
map::operator[] automatically creates the key/value pair if it doesn't exist.
(That's why it's not const!)
So you don't need to create the inner map manually.
If you want to avoid creating the pair automatically, then use map::find() or map::at().
I believe the simplest one-liner is:
(*nestedMap)[int][int] = int;
If i understand your question properly, you can actually use reference instead of pointer. You are not having issue with nested map, instead your outter map.
See below code, is what you want?
map<int, map<int, int> >* nestedMap = new map<int, map<int, int> >;
map<int, map<int, int> > &nestedMapAlais = *nestedMap;
nestedMapAlais[1][2] = 3;
access the operator[] via ->:
nestedMap->operator[](5)[6] = 7;
This is analogous to
nestedMap[5][6] = 7;
if nestedMap is not a pointer.
Note that in neither case do you have to explicitly insert a map.