Dereferencing member of a templated typedef - c++

I am using a library that has:
typedef std::map<std::wstring, std::vector<std::wstring>* > XmlRecord_t;
When I iterate on this map, I create variables such as:
std::wstring& key( mapIter->first );
std::vector<std::wstring>* values( mapIter->second );
which is all fine. Then I want to iterate on the values, so I have a for loop such as:
for( std::vector<std::wstring>::const_iterator it = vals->cbegin();... )
which is fine and works well.
Now, as a curiosity only, I'd like to reuse the library's typedef names, in case the typedef definition changes, or for cleanliness. In other words, I'd like to use:
typedef XmlRecord_t::mapped_type VecPtr;
VecPtr values( mapIter->second )
instead of:
std::vector<std::wstring>* values( mapIter->second );
That works so far. The only issue comes from the for loop. My typedef is a pointer to vector, not just a vector. So I cannot use that typedef to replace:
std::vector<std::wstring>::const_iterator
in any way I know of.
Hence, my question generalizes to: if you have in a library (code I do not allow you to modify):
typedef map<KEY, T*> Map2Ptrs
how can you use Map2Ptrs in your code to get T (without the pointer)? To make a typedef of type T?
Obviously, the library authors should have created:
typedef std::vector<std::wstring> XmlRecordVals;
typedef std::map<std::wstring, XmlRecordVals* > XmlRecord_t;
instead. But I only have the original XmlRecord_t above to work with ;(

Assuming Map2Ptrs is always an std::map, its key and mapped type can be inspected with Map2Ptrs::key_type and Map2Ptrs::mapped_type respectively.
The pointer can be removed from a type with std::remove_pointer_t (requires C++14 and #include<type_traits>), e.g.:
using T = std::remove_pointer_t<Map2Ptrs::mapped_type>;
In modern C++ you probably should not specify the iterator types by hand, they can easily be deduced:
for( auto it = vals->cbegin();... )
Furthermore, there is also the range-for, which eliminates the need to specify the iterators manually and has much nicer syntax:
for(const auto& x : *vals) { /* Do something with x */ }
And since C++17, for the map structured bindings can be used:
for(const auto& [key, vals] : theMap) {
/* Do something with key and vals */
}

There is std::remove_pointer. Example from cppreference:
print_is_same<int, std::remove_pointer<int*>::type>(); // true
So if your aliased the pointer to vector type then you'd get the iterator via:
using Xml_const_iterator = std::remove_pointer<XmlRecord_t>type::const_iterator;
Though I would strongly suggest you to change the actual alias to remove the pointer instead.

Related

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.

Determining if an element was inserted into a hash map

I'm using Google's sparsehashmap, and trying to work out if a value was inserted or looked up. The following works, but obviously it's looking it up twice. How do I do it without the double lookup?
Element newElement = Element();
bool inserted = ((*map).insert(pair<const int64, Element>(key, newElement))).second;
Element element = (*(((*map).insert(pair<const int64, Element>(key, newElement))).first)).second;
if (inserted)
puts("INSERTED");
I can't check the contents of Element (it's a struct) as I want to differentiate between a default Element being found and newElement being inserted. I couldn't work out how to assign ((*map).insert(pair<const int64, Element>(key, newElement))) to a variable as it's of a template type that includes types private to the sparse_hash_map class.
Try this:
typedef sparse_hash_map<...>::iterator sh_iterator; //you already have this, haven't you?
std::pair<sh_iterator, bool> res = map->insert(std::make_pair(key, newElement));
if (res.second)
puts("INSERTED");
If, for whatever reason you don't like the std::make_pair function, you should consider a typedef for the pair type:
typedef pair<const int64, Element> map_pair;
Anyway, the return type of insert is pair<iterator, bool>, and AFAIK iterator is a public typedef of the class.
BTW, I don't get why you do the second insert... to get to the inserted element? Probably you should declare element as a reference. In my suggested code:
Element &element = res.first->second;
Naturally, if you were using C++11, you could simply do:
auto res = ...;

Pointer to a map

If I define a pointer-to-map like this:
map<int, string>* mappings;
mappings is a pointer. How should I use this pointer to operate the map?
Use the pointer just like you use any other pointer: dereference it to get to the object to which it points.
typedef std::map<int, string>::iterator it_t;
it_t it1 = mappings->begin(); // (1)
it_t it2 = (*mappings).begin(); // (2)
string str = (*mappings)[0]; // (3)
Remember that a->b is — mostly — equivalent to (*a).b, then have fun!
(Though this equivalence doesn't hold for access-by-index like (*a)[b], for which you may not use the -> syntax.)
Not much difference except that you have to use -> for accessing the map members. i.e.
mapping->begin() or mapping->end()
If you don't feel comfortable with that then you can assign a reference to that and use it as in the natural way:
map<int, string> &myMap = *mappings; // 'myMap' works as an alias
^^^^^^^^
Use myMap as you generally use it. i.e.
myMap[2] = "2";
myMap.begin() or myMap.end();
For instance:
#include <map>
#include <string>
#include <iostream>
int main() {
std::map<int, std::string> * mapping = new std::map<int, std::string>();
(*mapping)[1] = "test";
std::cout << (*mapping)[1] <<std::endl;
}
With the introduction of "at" function in c++ 11, you can use mappings->at(key) instead of (*mapping)[key].
Keep in mind that this api will throw out_of_range exception if the key is not already available in the map.
another nice way of using pointers, which I like is calling mappings->(and the function you want to call)
Well, STL is designed to reduce the complexity of pointer handling..so better approach is to use stl::iterator.. try to avoid pointers :-/

Shorter way to get an iterator for a std::vector

Lets say that I have got a vector like this.
std::vector<a_complicated_whatever_identifier *> *something
= new std::vector<a_complicated_whatever_identifier *>;
// by the way, is this the right way to do this?
Now I want to get an iterator for this... so I would do this like this.
std::vector<a_complicated_whatever_identifier *>::iterator iter;
But I find it a little too much for my code. I wonder, is there any more, brief way to ask for an iterator regardless of the type?
I was thinking in something like.
something::iterator iter;
// OK, don’t laugh at me, I am still beginning with C++
Well, it obviously fail, but I guess you get the idea. How to accomplish this or something similar?
You would typically give your containers sensible typedefs, and then it's a breeze:
typedef std::pair<int, Employee> EmployeeTag;
typedef std::map<Foo, EmployeeTag> SignInRecords;
for (SignInRecords::const_iterator it = clock_ins.begin(); ... )
^^^^^^^^^^^^^^^^^
Usually, having a handy typedef for the container is more practical and self-documenting that an explicit typedef for the iterator (imagine if you're changing the container).
With the new C++ (11), you can say auto it = clock_ins.cbegin() to get a const-iterator.
Use a typedef.
typedef std::vector<complicated *>::iterator complicated_iter
Then set them like this:
complicated_iter begin, end;
In C++11 you'll be able to use auto.
auto iter = my_container.begin();
In the meantime just use a typedef for the vector:
typedef std::vector<a_complicated_whatever_identifier *> my_vector;
my_vector::iterator iter = my_container.begin();
You should rarely have much need/use for defining an iterator directly. In particular, iterating through a collection should normally be done by a generic algorithm. If there's one already defined that can do the job, it's best to use it. If there's not, it's best to write your own algorithm as an algorithm. In this case, the iterator type becomes a template parameter with whatever name you prefer (usually something referring at least loosely to the iterator category):
template <class InputIterator>
void my_algorithm(InputIterator start, InputIterator stop) {
for (InputIterator p = start; p != stop; ++p)
do_something_with(*p);
}
Since they've been mentioned, I'll point out that IMO, typedef and C++11's new auto are (at least IMO) rarely a good answer to this situation. Yes, they can eliminate (or at least reduce) the verbosity in defining an object of the iterator type -- but in this case, it's basically just treating the symptom, not the disease.
As an aside, I'd also note that:
A vector of pointers is usually a mistake.
Dynamically allocating a vector is even more likely a mistake.
At least right off, it looks rather as if you're probably accustomed to something like Java, where you always have to use new to create an object. In C++, this is relatively unusual -- most of the time, you want to just define a local object so creation and destruction will be handled automatically.
// by the way, is this the right way to do this?
What you are doing is correct. The best approach depends on how you want to use that vector.
But I find it a little too much for my code. I wonder, is there any
more, brief way to ask for an iterator regardless of the type?
Yes, you can define the vector as a type:
typedef std::vector<a_complicated_whatever_identifier *> MyVector;
MyVector * vectPtr = new MyVector;
MyVector::iterator iter;
If you have a recent compiler, I suggest giving c++11 a spin. Most compilers support it in the form of the --std=c++0x flag. You can do all kinds of nifty things related to type inference:
std::list<std::map<std::string, some_complex_type> > tables;
for (auto& table: tables)
{
std::cout << table.size() << std::endl;
}
for (auto it = tables.begin(); it!= tables.end(); ++it)
{
std::cout << it->size() << std::endl;
}
Also look at decltype and many other handyness:
// full copy is easy
auto clone = tables;
// but you wanted same type, no data?
decltype(tables) empty;
Contrived example of combining typedefs with the above:
typedef decltype(tables) stables_t;
typedef stables_t::value_type::const_iterator ci_t;

BOOST_FOREACH & templates without typedef

When I work with BOOST_FOREACH, there isn't a problem with simple templates as vector. But when I try to iterate through map > for example I need to typedef the element type.
Is there any workaround?
There is a problem because it is a macro, and therefore cannot handle types containing commas (preprocessor doesn't know about templates).
You can also declare the variable before the loop, see documentation.
std::map<int, double> my_map;
//1)
typedef std::pair<int, double> MyPair;
BOOST_FOREACH(MyPair p, my_map) { ... }
//2)
std::pair<int, double> p;
BOOST_FOREACH(p, my_map) { ... }
Edit:
There is a further complication with std::map in particular: the value_type is not std::pair<Key, Value>, but std::pair<const Key, Value>.
Hence, if you go with the typedef, a more proper way (and the only way if you want to use a reference in the foreach loop) is to use
typedef std::pair<const int, double> MyPair;
//or
typedef std::map<int, double>::value_type MyPair;
BOOST_FOREACH(MyPair& ref, my_map) { ... }
However, that won't work if you want to use a variable declared before the loop, since you can't assign to a std::pair<const int, double> instance later (can't assign to the const field), in which case you can only use pair<int, double> as boost's manual shows.
If you need to iterate over a map, the easiest way is to use tuples, since getting the correct type in order to typedef, is troublesome. Here is how you can use tuples:
std::map<int, double> my_map;
int key;
double value;
BOOST_FOREACH(boost::tie(key, value), my_map) { ... }
Just a note, the commas will work here because parenthesis are placed around key and value. The preprocessor only understands commas and parenthesis(and c99 requires it to understand quotation marks also). So, it can't parse the <> in std::pair<int, double>. However, we can use parenthesis to help the preprocessor. For example, if we have a a function that returns a container that is called like this:
BOOST_FOREACH(int i, foo<int, int>()) { ... } //This won't compile
So, we can place parenthesis around an expression and it will help the preprocessor:
BOOST_FOREACH(int i, (foo<int, int>())) { ... } //This will compile
However, in the case of a map, we can't place parenthesis around the declaration(because its not an expression). So this won't work:
BOOST_FOREACH((std::pair<int, double> p), my_map) { ... } //This won't work
Because it will get transformed into something like this (std::pair<int, double> p) = *it, and that, of course, is incorrect C++. But using a tie will work:
BOOST_FOREACH(tie(key, value), my_map) { ... } //This will work
We just need to declare key and value outside of the loop(as shown above). Plus, it can make the loop have more meaningful names. You can write key instead of p.first, and value instead of p.second.
BOOST_FOREACH_PAIR is another option that works well in our experience:
http://lists.boost.org/Archives/boost/2009/09/156345.php
http://lists.boost.org/Archives/boost/2009/09/156366.php
This can be as simple as this:
BOOST_FOREACH(auto& p, my_map) { ... }
Using the C++11 standard, auto is like var in C#, it will do
BOOST_FOREACH(std::pair<int, double>& p, my_map) { ... }