c++ insert empty vector can not use braces - c++

Codes below doesnt' works properly, when I reference to it, it causes Member call on null pointer error, if it's not supported, why it allow the use of insert(end, {})(No compile error).
#include <vector>
#include <iostream>
using namespace std;
int main() {
vector<vector<pair<int, int>>> vv;
auto it = vv.insert(vv.end(), {});
cout << it->size() << endl;
}
When I changed {} to vector<pair<int, int>>, no error shows and print 0.
Solved by comments, It calls iterator insert( const_iterator pos, std::initializer_list<T> ilist ), So change it to insert(end, {{}}) could work.

According to cppreference – std::vector<T,Allocator>::insert(), all flavors of insert() return the iterator of first inserted element or the insertion position if nothing was inserted.
In OPs exposed MCVE:
#include <vector>
#include <iostream>
using namespace std;
int main() {
vector<vector<pair<int, int>>> vv;
auto it = vv.insert(vv.end(), {});
cout << it->size() << endl;
}
the line
auto it = vv.insert(vv.end(), {});
doesn't use the
iterator insert( const_iterator pos, const T& value );
as it might be expected but the
iterator insert( const_iterator pos, std::initializer_list<T> ilist );.
Hence, there are 0 elements inserted and the insert() returns the end() iterator which was passed.
So,
cout << it->size() << endl;
accesses the contents of end() which is Undefined Behavior.
I made a small sample to demonstrate this:
#include <initializer_list>
#include <iostream>
#include <vector>
template <typename T>
struct Container: std::vector<T> {
using typename std::vector<T>::iterator;
using typename std::vector<T>::const_iterator;
iterator insert( const_iterator pos, const T& value )
{
std::cout << "insert single value\n";
return std::vector<T>::insert(pos, value);
}
iterator insert( const_iterator pos, std::initializer_list<T> ilist )
{
std::cout << "insert initializer list\n";
return std::vector<T>::insert(pos, ilist);
}
};
using namespace std;
int main() {
Container<vector<pair<int, int>>> vv;
auto it = vv.insert(vv.end(), {});
cout << /*it->*/vv.size() << endl;
}
Output:
insert initializer list
0
Live Demo on coliru
Note:
I'm aware that it's, at least, bad style to overload std::vector.
I did this exceptionally to show the used function call (and I didn't have a better idea how to achieve this).

The line auto it = vv.insert(vv.end(), {}); is using the form iterator insert( const_iterator pos, std::initializer_list<T> ilist );.
As int the line auto it = vv.insert(vv.end(), {});, the initlizer list have no element so no element is inserted in the vector vv.
As there is no element is inserted so it is same as vv.end() for which it is invalid to deference.
You can verify it via checking the length of vv after insertion. See sample code here to check it.

Related

need STL set in insertion order

How to store elements in set in insertion order.
for example.
set<string>myset;
myset.insert("stack");
myset.insert("overflow");
If you print, the output is
overflow
stack
needed output :
stack
overflow
One way is to use two containers, a std::deque to store the elements in insertion order, and another std::set to make sure there are no duplicates.
When inserting an element, check if it's in the set first, if yes, throw it out; if it's not there, insert it both in the deque and the set.
One common scenario is to insert all elements first, then process(no more inserting), if this is the case, the set can be freed after the insertion process.
A set is the wrong container for keeping insertion order, it will sort its element according to the sorting criterion and forget the insertion order. You have to use a sequenced container like vector, deque or list for that. If you additionally need the associative access set provides you would have to store your elements in multiple containers simultaneously or use a non-STL container like boost::multi_index which can maintain multiple element orders at the same time.
PS: If you sort the elements before inserting them in a set, the set will keep them in insertion order but I think that will not address your problem.
If you don't need any order besides the insertion order, you could also store the insert number in the stored element and make that the sorting criterion. However, why one would use a set in this case at all escapes me. ;)
Here's how I do it:
template <class T>
class VectorSet
{
public:
using iterator = typename vector<T>::iterator;
using const_iterator = typename vector<T>::const_iterator;
iterator begin() { return theVector.begin(); }
iterator end() { return theVector.end(); }
const_iterator begin() const { return theVector.begin(); }
const_iterator end() const { return theVector.end(); }
const T& front() const { return theVector.front(); }
const T& back() const { return theVector.back(); }
void insert(const T& item) { if (theSet.insert(item).second) theVector.push_back(item); }
size_t count(const T& item) const { return theSet.count(item); }
bool empty() const { return theSet.empty(); }
size_t size() const { return theSet.size(); }
private:
vector<T> theVector;
set<T> theSet;
};
Of course, new forwarding functions can be added as needed, and can be forwarded to whichever of the two data structures implements them most efficiently. If you are going to make heavy use of STL algorithms on this (I haven't needed to so far) you may also want to define member types that the STL expects to find, like value_type and so forth.
If you can use Boost, a very straightforward solution is to use the header-only library Boost.Bimap (bidirectional maps).
Consider the following sample program that will display your dummy entries in insertion order (try out here):
#include <iostream>
#include <string>
#include <type_traits>
#include <boost/bimap.hpp>
using namespace std::string_literals;
template <typename T>
void insertCallOrdered(boost::bimap<T, size_t>& mymap, const T& element) {
// We use size() as index, therefore indexing with 0, 1, ...
// as we add elements to the bimap.
mymap.insert({ element, mymap.size() });
}
int main() {
boost::bimap<std::string, size_t> mymap;
insertCallOrdered(mymap, "stack"s);
insertCallOrdered(mymap, "overflow"s);
// Iterate over right map view (integers) in sorted order
for (const auto& rit : mymap.right) {
std::cout << rit.first << " -> " << rit.second << std::endl;
}
}
I'm just wondering why nobody has suggested using such a nice library as Boost MultiIndex. Here's an example how to do that:
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/indexed_by.hpp>
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <iostream>
template<typename T>
using my_set = boost::multi_index_container<
T,
boost::multi_index::indexed_by<
boost::multi_index::sequenced<>,
boost::multi_index::ordered_unique<boost::multi_index::identity<T>>
>
>;
int main() {
my_set<int> set;
set.push_back(10);
set.push_back(20);
set.push_back(3);
set.push_back(11);
set.push_back(1);
// Prints elements of the set in order of insertion.
const auto &index = set.get<0>();
for (const auto &item : index) {
std::cout << item << " ";
}
// Prints elements of the set in order of value.
std::cout << "\n";
const auto &ordered_index = set.get<1>();
for (const auto &item : ordered_index) {
std::cout << item << " ";
}
}
what you need is this, very simple and a standard library. Example online compiler link: http://cpp.sh/7hsxo
#include <iostream>
#include <string>
#include <unordered_set>
static std::unordered_set<std::string> myset;
int main()
{
myset.insert("blah");
myset.insert("blah2");
myset.insert("blah3");
int count = 0;
for ( auto local_it = myset.begin(); local_it!= myset.end(); ++local_it ) {
printf("index: [%d]: %s\n", count, (*local_it).c_str());
count++;
}
printf("\n");
for ( unsigned i = 0; i < myset.bucket_count(); ++i) {
for ( auto local_it = myset.begin(i); local_it!= myset.end(i); ++local_it )
printf("bucket: [%d]: %s\n", i, (*local_it).c_str());
}
}

Implementing a custom iterator returning data from 2 vectors [duplicate]

I'd like to replicate the following with BOOST FOREACH
std::vector<int>::const_iterator i1;
std::vector<int>::const_iterator i2;
for( i1 = v1.begin(), i2 = v2.begin();
i1 < v1.end() && i2 < v2.end();
++i1, ++i2 )
{
doSomething( *i1, *i2 );
}
Iterating over two things simultaneously is called a "zip" (from functional programming), and Boost has a zip iterator:
The zip iterator provides the ability to parallel-iterate over several
controlled sequences simultaneously. A zip iterator is constructed
from a tuple of iterators. Moving the zip iterator moves all the
iterators in parallel. Dereferencing the zip iterator returns a tuple
that contains the results of dereferencing the individual iterators.
Note that it's an iterator, not a range, so to use BOOST_FOREACH you're going to have to stuff two of them into an iterator_range or pair. So it won't be pretty, but with a bit of care you can probably come up with a simple zip_range and write:
BOOST_FOREACH(boost::tuple<int,int> &p, zip_range(v1, v2)) {
doSomething(p.get<0>(), p.get<1>());
}
Or special-case for 2 and use std::pair rather than boost::tuple.
I suppose that since doSomething might have parameters (int&, int&), actually we want a tuple<int&,int&>. Hope it works.
If you use boost, I think it should be as simple as:
#include <boost/foreach.hpp>
#include <boost/range/combine.hpp>
std::vector<int> v1;
std::vector<int> v2;
// iterate over values
int i1, i2;
BOOST_FOREACH(boost::tie(i1, i2), boost::combine(v1, v2))
std::cout << i1+i2 << "\n"; // sums two vectors
// iterate over references
typedef boost::tuple<int&, int&> int_ref_tuple;
BOOST_FOREACH(int_ref_tuple tup, boost::combine(v1, v2))
tup.get<0>() = tup.get<1>(); // assigns one vector to another
the strange part is that boost::combine is not documented. Works for me, anyway.
If you want to use BOOST_FOREACH to iterate two vectors simultenously, as you've done in your sample code, then you've to encapsulate both vectors in a wrapper class which should expose begin and end functions. These functions return custom iterator to be used to iterate over the wrapper which internally will iterate over the two vectors. Doesn't sound good, but that is what you've to do.
This is my first attempt to implement this (minimal implementation just to demonstrate the basic idea):
template<typename T>
struct wrapper
{
struct iterator
{
typedef typename std::vector<T>::iterator It;
It it1, it2;
iterator(It it1, It it2) : it1(it1), it2(it2) {}
iterator & operator++()
{
++it1; ++it2; return *this;
}
iterator & operator *()
{
return *this;
}
bool operator == (const iterator &other)
{
return !(*this != other);
}
bool operator != (const iterator &other)
{
return it1 != other.it1 && it2 != other.it2;
}
};
iterator begin_, end_;
wrapper(std::vector<T> &v1, std::vector<T> &v2)
: begin_(v1.begin(), v2.begin()),end_(v1.end(), v2.end())
{
}
wrapper(const wrapper & other) : begin_(other.begin_), end_(other.end_) {}
iterator begin()
{
return begin_;
}
iterator end()
{
return end_;
}
};
And the following is the test code. Since it's using usual for loop, because ideone has not installed for boost for C++0x or I'm doing something wrong when including it.
int main() {
std::vector<int> v1 = {1,2,3,4,5,6};
std::vector<int> v2 = {11,12,13,14,15};
wrapper<int> w(v1,v2);
for(wrapper<int>::iterator it = w.begin(); it != w.end(); ++it)
{
std::cout << *it.it1 <<", "<< *it.it2 << std::endl;
}
return 0;
}
Output:
1, 11
2, 12
3, 13
4, 14
5, 15
Demo : http://ideone.com/Hf667
This is good for experimentation and learning purpose only, as I don't claim it to be perfect. There can be lots of improvement. And #Steve already has posted boost's solution.
Thanks to the answer of Steve Jessop and the great comments, I came up to the following solution, so if you find that nice, vote up Steve Jessop answer first. ;)
#include <iostream>
#include <vector>
#include <boost/typeof/typeof.hpp>
#include <boost/typeof/std/vector.hpp>
#include <boost/foreach.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/iterator/zip_iterator.hpp>
#include <boost/range/iterator_range.hpp>
using namespace boost;
int main(int argc, char **argv) {
std::vector<int> vecFirst = assign::list_of(1)(2)(3)(43)(7)(13);
std::vector<double> vecSecond = assign::list_of(53.45)(-23.545)(0.1574)(1.001)(0.0047)(9.7);
BOOST_AUTO(zipSequence,
make_iterator_range(
make_zip_iterator(make_tuple(vecFirst.begin(), vecSecond.begin())),
make_zip_iterator(make_tuple(vecFirst.end(), vecSecond.end()))
)
);
BOOST_FOREACH( BOOST_TYPEOF(*zipSequence.begin()) each, zipSequence) {
std::cout << "First vector value : " << each.get<0>()
<< " - Second vector value : " << each.get<1>()
<< std::endl;
}
}

How can I order a map by value efficiently?

Consider a std::map<K,V>. I want to re-order the map by value profiting by an appropriate container std::C<V*> or std::C<V&>, in a way that no copies of values are done to store the elements in C. Furthermore, elements in C must be sorted according to the result of int f(V&) applied to each element. Despite my efforts I could not find an appropriate C and an enough efficient way to build it. Do you have any solution? A small example would be much appreciated.
Seems simple enough.
std::map<K,V> src;
int f(V&) {return 0;}
V* get_second(std::pair<const K,V> &r) {return &(r.second);} //transformation
bool pred(V* l, V* r) { return f(*l)<f(*r); } //sorting predicate
std::vector<V*> dest(src.size()); //make destination big enough
std::transform(src.begin(), src.end(), dest.begin(), get_second); //transformcopy
std::sort(dest.begin(), dest.end(), pred); //sort
Unless you meant C is supposed to be another map:
std::pair<K,V*> shallow_pair(std::pair<const K,V> &r)
{return std::pair<K,V*>(r.first, &(r.second));}
std::map<K, V*> dest2;
std::transform(src.begin(), src.end(),
std::inserter(dest2,dest2.end()), shallow_pair);
http://ideone.com/bBoXq
This requires the previous map to remain in scope longer than dest, and have no pairs removed until dest is destructed. Otherwise src will need to have been holding smart pointers of some sort.
You can use std::reference_wrapper, like this:
#include <map>
#include <string>
#include <algorithm>
#include <functional>
#include <prettyprint.hpp>
#include <iostream>
template <typename T>
std::ostream & operator<<(std::ostream & o, std::reference_wrapper<T> const & rw)
{
return o << rw.get();
}
int main()
{
std::map<int, std::string> m { { 1, "hello"}, { 2, "aardvark" } };
std::cout << m << std::endl;
std::vector<std::reference_wrapper<std::string>> v;
for (auto & p : m) v.emplace_back(p.second);
std::cout << v << std::endl;
std::sort(v.begin(), v.end(), std::less<std::string>); // or your own predicate
std::cout << v << std::endl;
v.front().get() = "world";
std::cout << m << std::endl;
}
This prints:
[(1, hello), (2, aardvark)]
[hello, aardvark]
[aardvark, hello]
[(1, hello), (2, world)]
Sounds like you are using multiple containers to represent multiple views into the same dataset. The trouble with this approach is in keeping the containers synchronized and avoiding dangling pointer issues. Boost.MultiIndex was made for just this purpose. A boost::multi_index container stores only one copy of each element, but allows you to access the elements via several indices.
Example:
#include <iterator>
#include <iostream>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/global_fun.hpp>
#include <boost/multi_index/member.hpp>
typedef std::string Key;
typedef int Value;
struct Record
{
Record(const Key& key, Value value) : key(key), value(value) {}
Key key;
Value value;
};
inline std::ostream& operator<<(std::ostream& os, const Record& rec)
{
os << rec.key << " " << rec.value << "\n";
return os;
}
inline int sortFunc(const Record& rec) {return -rec.value;}
struct ByNumber{}; // tag
namespace bmi = boost::multi_index;
typedef bmi::multi_index_container<
Record,
bmi::indexed_by<
// sort by key like a std::map
bmi::ordered_unique< bmi::member<Record, Key, &Record::key> >,
// sort by less<int> on free function sortFunc(const Record&)
bmi::ordered_non_unique<bmi::tag<ByNumber>,
bmi::global_fun<const Record&, int, &sortFunc> >
>
> RecordSet;
typedef RecordSet::index<ByNumber>::type RecordsByNumber;
int main()
{
RecordSet rs;
rs.insert(Record("alpha", -1));
rs.insert(Record("charlie", -2));
rs.insert(Record("bravo", -3));
RecordsByNumber& byNum = rs.get<ByNumber>();
std::ostream_iterator<Record> osit(std::cout);
std::cout << "Records sorted by key:\n";
std::copy(rs.begin(), rs.end(), osit);
std::cout << "\nRecords sorted by sortFunc(const Record&):\n";
std::copy(byNum.begin(), byNum.end(), osit);
}
Result:
Records sorted by key:
alpha -1
bravo -3
charlie -2
Records sorted by sortFunc(const Record&):
alpha -1
charlie -2
bravo -3
The place I'd start is to:
look at Boost::bimap
create ordering from V -> K via a comparator function object which evaluates f(V&) the way you suggested. (e.g. as in std::map<K,V,C> where C is a comparator class)
How about,
std::set<boost::shared_ptr<V>, compfunc>
where compfunc is a functor which takes two shared_ptr objects and applies the logic in your function?
Excuse the formatting, not good on my phone.
How about something like this (untested pseudo code):
V* g(pair<K,V> &v) { return &v.second; }
bool cmp(V* a, V* b) { return f(*a) < f(*b); }
map<K,V> map;
vector<V*> vec;
vec.reserve(map.size());
transform(map.begin(), map.end(), back_inserter(vec), g);
sort(vec.begin(), vec.end(), cmp);

How can I iterate over two vectors simultaneously using BOOST_FOREACH?

I'd like to replicate the following with BOOST FOREACH
std::vector<int>::const_iterator i1;
std::vector<int>::const_iterator i2;
for( i1 = v1.begin(), i2 = v2.begin();
i1 < v1.end() && i2 < v2.end();
++i1, ++i2 )
{
doSomething( *i1, *i2 );
}
Iterating over two things simultaneously is called a "zip" (from functional programming), and Boost has a zip iterator:
The zip iterator provides the ability to parallel-iterate over several
controlled sequences simultaneously. A zip iterator is constructed
from a tuple of iterators. Moving the zip iterator moves all the
iterators in parallel. Dereferencing the zip iterator returns a tuple
that contains the results of dereferencing the individual iterators.
Note that it's an iterator, not a range, so to use BOOST_FOREACH you're going to have to stuff two of them into an iterator_range or pair. So it won't be pretty, but with a bit of care you can probably come up with a simple zip_range and write:
BOOST_FOREACH(boost::tuple<int,int> &p, zip_range(v1, v2)) {
doSomething(p.get<0>(), p.get<1>());
}
Or special-case for 2 and use std::pair rather than boost::tuple.
I suppose that since doSomething might have parameters (int&, int&), actually we want a tuple<int&,int&>. Hope it works.
If you use boost, I think it should be as simple as:
#include <boost/foreach.hpp>
#include <boost/range/combine.hpp>
std::vector<int> v1;
std::vector<int> v2;
// iterate over values
int i1, i2;
BOOST_FOREACH(boost::tie(i1, i2), boost::combine(v1, v2))
std::cout << i1+i2 << "\n"; // sums two vectors
// iterate over references
typedef boost::tuple<int&, int&> int_ref_tuple;
BOOST_FOREACH(int_ref_tuple tup, boost::combine(v1, v2))
tup.get<0>() = tup.get<1>(); // assigns one vector to another
the strange part is that boost::combine is not documented. Works for me, anyway.
If you want to use BOOST_FOREACH to iterate two vectors simultenously, as you've done in your sample code, then you've to encapsulate both vectors in a wrapper class which should expose begin and end functions. These functions return custom iterator to be used to iterate over the wrapper which internally will iterate over the two vectors. Doesn't sound good, but that is what you've to do.
This is my first attempt to implement this (minimal implementation just to demonstrate the basic idea):
template<typename T>
struct wrapper
{
struct iterator
{
typedef typename std::vector<T>::iterator It;
It it1, it2;
iterator(It it1, It it2) : it1(it1), it2(it2) {}
iterator & operator++()
{
++it1; ++it2; return *this;
}
iterator & operator *()
{
return *this;
}
bool operator == (const iterator &other)
{
return !(*this != other);
}
bool operator != (const iterator &other)
{
return it1 != other.it1 && it2 != other.it2;
}
};
iterator begin_, end_;
wrapper(std::vector<T> &v1, std::vector<T> &v2)
: begin_(v1.begin(), v2.begin()),end_(v1.end(), v2.end())
{
}
wrapper(const wrapper & other) : begin_(other.begin_), end_(other.end_) {}
iterator begin()
{
return begin_;
}
iterator end()
{
return end_;
}
};
And the following is the test code. Since it's using usual for loop, because ideone has not installed for boost for C++0x or I'm doing something wrong when including it.
int main() {
std::vector<int> v1 = {1,2,3,4,5,6};
std::vector<int> v2 = {11,12,13,14,15};
wrapper<int> w(v1,v2);
for(wrapper<int>::iterator it = w.begin(); it != w.end(); ++it)
{
std::cout << *it.it1 <<", "<< *it.it2 << std::endl;
}
return 0;
}
Output:
1, 11
2, 12
3, 13
4, 14
5, 15
Demo : http://ideone.com/Hf667
This is good for experimentation and learning purpose only, as I don't claim it to be perfect. There can be lots of improvement. And #Steve already has posted boost's solution.
Thanks to the answer of Steve Jessop and the great comments, I came up to the following solution, so if you find that nice, vote up Steve Jessop answer first. ;)
#include <iostream>
#include <vector>
#include <boost/typeof/typeof.hpp>
#include <boost/typeof/std/vector.hpp>
#include <boost/foreach.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/iterator/zip_iterator.hpp>
#include <boost/range/iterator_range.hpp>
using namespace boost;
int main(int argc, char **argv) {
std::vector<int> vecFirst = assign::list_of(1)(2)(3)(43)(7)(13);
std::vector<double> vecSecond = assign::list_of(53.45)(-23.545)(0.1574)(1.001)(0.0047)(9.7);
BOOST_AUTO(zipSequence,
make_iterator_range(
make_zip_iterator(make_tuple(vecFirst.begin(), vecSecond.begin())),
make_zip_iterator(make_tuple(vecFirst.end(), vecSecond.end()))
)
);
BOOST_FOREACH( BOOST_TYPEOF(*zipSequence.begin()) each, zipSequence) {
std::cout << "First vector value : " << each.get<0>()
<< " - Second vector value : " << each.get<1>()
<< std::endl;
}
}

display map every time it is updated sorted by value

basically, I have the
map<std::string, int>
so if i have
foo 5
bar 10
jack 3
in the map, I want to display it (notice the reverse order)
bar 10
foo 5
jack 3
And every time it is updated, I want iterate through all the elements, cout them, sorted by value. What is the good way to implement that? should I provide a comparator to the constructor?
I want to note that values in the map will be updated at least 100 million times, so efficiency is crucial, where as extra-space is no problem
Please no Boost solutions...thx
struct keyval_t { std::string key; int val; };
int operator<(const keyval_t &a, const ketval_t &b)
{ return a.val<b.val || (a.val==b.val && a.key<b.key); }
Then you need one map and one set:
map<std::string, int>; set<keyval_t>;
On update, you need to look up the map first to determine the key-value pair and then update both map and set. On printing, you just iterate through the set. In terms of theoretical time complexity, this is optimal. It doubles the memory, though. Does this meet your goal?
To reduce memory, you may consider the following:
map<std::string,uint64_t>; set<uint64_t>;
The value of the map (also the key of the set) is: (uint64_t)val<<32|counter, where counter is something that differentiates identical values. For example, whenever you insert a key, increase the counter by 1. You do not need to update the counter when you update the value. If you do not like uint64_t, use pair<int,int> instead. This solution is also faster as it avoids comparisons between strings.
If you want a performant map sorted by both key and value, you want Boost MultiIndex, it gets updated (resorted) on every update (which you have to do manually) and has a good documentation.
The previous responses have the inconvenience not to take into account the initial requirements (the key is std::string and the value is int).
EDITED: following the comments, I suppose presenting it directly with a Bimap is better :)
So here we go, right in!
#include <boost/bimap.hpp>
class MyMap
{
struct name {};
struct value {};
typedef boost::tagged<name, std::string> tagged_name;
typedef boost::tagged<value, int> tagged_value;
// unordered_set_of: guarantees only unicity (not order)
// multi_set_of: guarantees only order (not unicity)
typedef boost::bimap< boost::unordered_set_of< tagged_name >,
boost::multi_set_of< tagged_value,
std::greater< tagged_value >
>
> impl_type;
public:
// Redefine all usual types here
typedef typename impl_type::map_by<name>::const_iterator const_iterator;
typedef typename impl_type::value_type value_type;
// Define the functions you want
// the bimap will not allow mutators because the elements are used as keys
// so you may want to add wrappers
std::pair< iterator, bool > insert(const value_type & x)
{
std::pair< iterator, bool > result = m_impl.insert(x);
if (result.second) this->display();
return result;
} // insert
iterator insert(iterator position, const value_type & x)
{
iterator result = m_impl.insert(x);
this->display();
return result;
} // insert
template< class InputIterator >
void insert(InputIterator first, InputIterator last)
{
m_impl.insert(first, last);
this->display();
} // insert
private:
void display() const
{
// Yeah I know about std::for_each...
typedef typename impl_type::map_by<value>::const_iterator const_it;
for (const_it it = m_impl.begin(), end = m_impl.end(); it != end; ++it)
{
// Note the inversion of the 'second' and 'first',
// we are looking at it from the right
std::cout << it->second << " " << it->first << std::endl;
}
}
impl_type m_impl;
}; // class MyMap
Here you go.
I strongly suggest that you consult the bimap documentation though. There are a lot of possibilities for storing (set_of, unordered_set_of, unconstrained_set_of, the muli variants, the list_of variant...) so there is probably one that could do what you want.
Then you also have the possibility to just sort each time you display:
#include <set>
#include <map>
// Just use a simple std::map<std::string,int> for your impl_type
// Mutators are allowed since the elements are sorted each time you display
struct Comparator
{
bool operator(const value_type& lhs, const value_type& rhs) const
{
return lhs.second < rhs.value;
}
};
void display() const
{
typedef std::multi_set<value_type, Comparator> sort_type;
sort_type mySet;
std::copy(m_impl.begin(), m_impl.end(), std::inserter(mySet, mySet.end()));
for (sort_type it = mySet.begin(), end = mySet.end(); it != end; ++it)
{
std::cout << it->first<< " " << it->second << std::endl;
}
}
It should be easier to understand my point now :)
Well, you have to sort by key. The easiest way to "sort by value" is to use a multimap with the key and value switched. So here's a way to do that (note -- i don't have access to a compiler right now, so if it doesn't compile, I'm sorry):
#include <algorithm>
#include <functional>
#include <map>
#include <string>
#include <utility>
typedef std::multimap<int, std::string, std::greater<int> > MapType;
struct MapKeyOutput
{
void operator()(const MapType::value_type& val)
{
std::cout << val.second << " " << val.first << "\n";
}
}
void display_insert(MapType& m, const std::string& str, int val)
{
m.insert(std::make_pair(val, str));
std::for_each(m.begin(), m.end(), MapKeyOutput());
}
int main()
{
MapType m;
display_insert(m, "Billy", 5);
display_insert(m, "Johnny", 10);
}
You could also make a map class that uses a multimap internally, I just didn't want to type it out. Then display_insert would be some member function instead. This should demonstrate the point, though. Points of interest:
typedef std::multimap<int, std::string, std::greater<int> > MapType;
Note the comparator is greater<int> to sort descending. We're using a multimap so more than one name can have the same number.
struct MapKeyOutput
{
void operator()(const MapType::value_type& val)
{
std::cout << val.second << " " << val.first << "\n";
}
}
This is a function object to output one element in the map. second is output before first so the order is what you want.
std::for_each(m.begin(), m.end(), MapKeyOutput());
This applies our function object to every element in m.