I have a boost::multi_index class which has multiple indexes.
If i want to store a normal iterator i can do
multi_index_table::const_iterator x_itr == my_table.find(x);
but if i try
multi_index_table::const_iterator x_itr == my_table.get_index(y).find(x) it complains that it's not the same type of iterator.
I'm fairly new to C++ and come from a java background, ideally i'd like some form of superclass which is able to store any type of iterator if that's possibile.
Any guidance will be much appreciated!
EDIT:
I'm basically looking to do something as such:
my_table.get_index(a).find(x);
x.erase<a>(x):
my_table.get_index(b).find(y);
x.erase<b>(y):
template<uint64_t Index>
template<typename Iterator>
Iterator erase(Iterator itr){
my_table.get_index<Index>().erase(itr)
}
With c++11 is rather easy. Just use:
auto x_itr = my_table.get_index(y).find(x)
The compiler will figure out the type of x_itr.
Related
So I wrote this code which won't compile. I think the reason is because std::transform, when given an iterator range such as this will operate on the type pointed to by the iterator, not the iterator itself. Is there any simple wrapper, standard lib tool, etc. to make this code work i.e. to store all the iterators of the original map into a new vector, with minimum changes required? Thanks!
#include <map>
#include <iostream>
#include <vector>
using MT = std::multimap<char, int>;
using MTI = MT::iterator;
int main()
{
MT m;
m.emplace('a', 1); m.emplace('a', 2); m.emplace('a', 3);
m.emplace('b', 101);
std::vector<MTI> itrs;
std::transform(m.begin(), m.end(), std::back_inserter(itrs), [](MTI itr){
return itr;
});
}
EDIT 1: Failed to compile with gcc11 and clang13, C++17/20
EDIT 2: The purpose of the question is mostly out of curiosity. I want to see what's a good way to manipulate existing standard algorithm to work on the level that I want. The sample code and problem are entirely made up for demonstration but they are not related to any real problem that requires a solution
Is there such a wrapper? Not in the standard. But it doesn't mean you can't write one, even fairly simply.
template<typename It>
struct PassIt : It {
It& operator*() { return *this; }
It const& operator*() const { return *this; }
PassIt & operator++() { ++static_cast<It&>(*this); return *this; }
PassIt operator++(int) const { return PassIt{static_cast<It&>(*this)++}; }
};
template<typename It>
PassIt(It) -> PassIt<It>;
That is just an example1 of wrapper that is a iterator of the specified template parameter type. It delegates to its base for the bookkeeping, while ensuring the the return types conform to returning the wrapped iterator itself when dereferencing.
You can use it in your example to simply copy the iterators
std::copy(PassIt{m.begin()}, PassIt{m.end()}, std::back_inserter(itrs));
See it live
(1) - It relies on std::iterator_traits deducing the correct things. As written in this example, it may not conform to all the requirements of the prescribed iterator type (in this case, we aimed at a forward iterator). If that happens, more boiler-plate will be required.
The function you pass to std::transform and algorithms in general are supposed to use elements not iterators. You could use the key to find the iterator in the map, though thats neither efficient nor simple. Instead use a plain loop:
for (auto it = m.begin(); it != m.end(); ++it) itrs.push_back(it);
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.
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;
I have a sequence of values that I'd like to pass to a function that takes a (iterator begin, iterator end) pair. However, I only want every second element in the original sequence to be processed.
Is there a nice way using Standard-Lib/Boost to create an iterator facade that will allow me to pass in the original sequence? I figured something simple like this would already be in the boost iterators or range libraries, but I didn't find anything.
Or am I missing another completely obvious way to do this? Of course, I know I always have the option of copying the values to another sequence, but that's not what I want to do.
Edit: I know about filter_iterator, but that filters on values - it doesn't change the way the iteration advances.
I think you want boost::adaptors::strided
struct TrueOnEven {
template< typename T >
bool operator()(const T&) { return mCount++ % 2 == 0; }
TrueOnEven() : mCount(0) {}
private:
int mCount;
};
int main() {
std::vector< int > tVec, tOtherVec;
...
typedef boost::filter_iterator< TrueOnEven, int > TakeEvenFilterType;
std::copy(
TakeEvenFilterType(tVec.begin(), tVec.end()),
TakeEvenFilterType(tVec.end(), tVec.end()),
std::back_inserter(tOtherVec));
}
To be honest, this is anything else than nice and intuitive. I wrote a simple "Enumerator" library including lazy integrated queries to avoid hotchpotch like the above. It allows you to write:
Query::From(tVec.begin(), tVec.end())
.Skip<2>()
.ToStlSequence(std::back_inserter(tOtherVec));
where Skip<2> basically instantiates a generalized "Filter" which skips every N-th (in this case every second) element.
Here's Boost's filter iterator. It is exactly what you want.
UPDATE: Sorry, read wrongly-ish. Here's a list of all iterator funkiness in Boost:
http://www.boost.org/doc/libs/1_46_1/libs/iterator/doc/#specialized-adaptors
I think a plain iterator_adaptor with an overloaded operator++ that increments the underlying iterator value twice is all you need.
I have a need to wrap a vector iterator, but don't like the idea to rewrite it from scratch. And I can't subclass it as far as vector iterator doesn't seem to be cross-platform. At least gnu and ibm ones look different.
What I want to do is the following:
class MyContainer {
vector<double> data;
vector<int> indices;
iterator
begin()
{ return my_iterator(data, indices.begin()); }
iterator
end()
{ return my_iterator(data, indices.end()); }
}
MyContainer cont;
Where indices vector contains integer positions within the data vector. Data is supposed to be much much bigger than the indices.
So I need an iterator that can go through the indices in any direction like a normal vector iterator does with the only exception: it must return a value of data vector when the value is going to be accessed. e.g.:
for(MyContainer::iterator it = cont.begin(); it != cont.end(); it++) {
cout << *it << endl; // values of data should appear here
}
Basically it should look like a normal collection for the std world. You can iterate it in whatever direction you want, you can sort it, run unique, find_if, etc...
any simple solution?
There's a great Boost library for defining custom iterators. You need to provide a class with a few methods:
i.dereference() Access the value referred to
i.equal(j) Compare for equality with j
i.increment() Advance by one position
i.decrement() Retreat by one position
i.advance(n) Advance by n positions
i.distance_to(j) Measure the distance to j
Then you get the rest from the iterator_facade.
Good luck!
This looks a lot like a permutation_iterator, one of the "built in" adapters from the Boost.Iterator Library
See this example (modified from the Boost docs) on codepad.
There's nothing in the standard C++ library, but you can probably get boost::iterator_adapter to do what you want. A preliminary examination suggests you'll need to override iterator_adapter::dereference and iterator_adapter::equal.
template <typename _Scalar=double,
typename _Idx=int,
typename _Seq=std::vector<_Scalar>,
typename _IdxVector=std::vector<_Idx> >
class SelIter
: public boost::iterator_adaptor< SelIter<_Scalar, _Idx>,
typename _IdxVector::iterator, _Scalar >
{
public:
typedef boost::iterator_adaptor< SelIter, typename _IdxVector::iterator, _Scalar > Base;
SelIter(_Seq& scalars, _IdxVector& idxs);
SelIter(_Seq& scalars, typename _IdxVector::iterator pi);
typename Base::reference dereference() const;
bool equal(const SelIter& x) const;
private:
// ...
}