Related
The function
template <typename Container, typename Comparator, typename Predicate>
void sortButKeepSomeFixed (Container& c, const Comparator& comp, const Predicate& pred)
is to sort the container c according to the ordering criterion comp, but those elements that satisfy pred shall remain fixed in their original positions after the sort (i.e. unaffected by the sort).
I tried to adapt quick sort to fit this, but could not think of it. In the end, I decided to adapt the crude selection sort to get the job done:
#include <iostream>
#include <vector>
std::vector<int> numbers = {5,7,1,8,9,3,20,2,11};
template <typename Container, typename Comparator, typename Predicate>
void sortButKeepSomeFixed (Container& c, const Comparator& comp, const Predicate& pred) { // O(n^2), but want O(nlogn) on average (like quick sort or merge sort)
const std::size_t N = c.size();
std::size_t i, j, minIndex;
for (i = 0; i < N-1; i++) {
if (pred(c[i]))
continue; // c[i] shall not swap with any element.
minIndex = i;
for (j = i + 1; j < N; j++) {
if (pred(c[j]))
continue; // c[j] shall not swap with any element.
if (comp(c[j], c[minIndex]))
minIndex = j;
}
if (minIndex != i)
std::swap(c[i], c[minIndex]);
}
}
int main() {
sortButKeepSomeFixed (numbers,
std::greater<int>(), // Ordering condition.
[](int x) {return x % 2 == 0;}); // Those that shall remain fixed.
for (int x : numbers) std::cout << x << ' '; // 11 9 7 8 5 3 20 2 1
}
But the time complexity is O(N^2) (I think). Can someone improve on the time complexity here, to perhaps O(NlogN) on average? In other words, find an overall better algorithm, using recursion or something like that?
Or perhaps a better idea is to take out the elements that satisfy pred, sort what left with std::sort and then put the extracted elements back in their original positions? Would that be any more efficient, or would that just make it worse?
Update:
This is based on Beta's suggestion (sorting the iterators that don't pass pred). But though the elements that pass pred do indeed remain fixed, the sorting at the end is not correct.
template <typename Container, typename Comparator, typename Predicate>
void sortButKeepSomeFixed (Container& c, const Comparator& comp, const Predicate& pred) {
std::vector<typename Container::iterator> iterators;
for (typename Container::iterator it = c.begin(); it != c.end(); ++it) {
if (!pred(*it))
iterators.emplace_back(it);
}
std::vector<typename Container::iterator> originalIterators = iterators;
std::sort(iterators.begin(), iterators.end(),
[comp](const typename Container::iterator& x, const typename Container::iterator& y)
{return comp(*x, *y);});
for (int i = 0; i < originalIterators.size(); i++)
*originalIterators[i] = *iterators[i];
}
The incorrect output is 11 9 9 8 11 3 20 2 9 when it should be 11 9 7 8 5 3 20 2 1.
That's a fun one. I first tried to code the IMO correct approach, using a custom iterator that just skips elements that satisfy the predicate. This turned out to be quite challenging, at least writing that on a mobile phone as I'm doing it.
Basically, this should lead to code similar to what you can find in Eric Niebler's ranges v3.
But there's also the simpler, direct approach that you're trying to use above. The problem of your non working solution is, that it's changing the values the (rest of the sorted) iterators point to when assigning in that last for loop. This issue can be avoided by having a copy, like in my code:
int main(int, char **) {
vector<int> input {1,2,3,4,5,6,7,8,9};
vector<reference_wrapper<int>> filtered{begin(input), end(input)};
filtered.erase(remove_if(begin(filtered), end(filtered),
[](auto e) {return e%2==0;}), end(filtered));
vector<int> sorted{begin(filtered), end(filtered)};
// change that to contain reference wrappers to see the issue
sort(begin(sorted), end(sorted),
greater<int>{});
transform(begin(filtered), end(filtered),
begin(sorted),
begin(filtered),
[](auto to, auto from) {
to.get() = from; return to;});
copy(begin(input), end(input),
ostream_iterator<int>{cout, ", "});
return 0;
}
Live example here. Forgot to fork before modifying, sorry.
(Instead of using copies at last for types that are using heap allocated data move should probably be used. Though I'm not sure whether you can assign to a moved from object.)
Using a ... rather weird ... wrapper class instead of the std::reference_wrapper makes it possible to achieve the filtered sorting without having to use a vector with (copied or moved) elements of the value type:
template <class T>
class copyable_ref {
public:
copyable_ref(T& ref) noexcept
: _ptr(std::addressof(ref)), _copied(false) {}
copyable_ref(T&&) = delete;
copyable_ref(const copyable_ref& x) noexcept
: _ptr (new int(*x._ptr)), _copied (true) {
}
~copyable_ref() {
if (_copied) {
delete _ptr;
}
}
copyable_ref& operator=(const copyable_ref& x) noexcept {
*_ptr = *x._ptr;
}
operator T& () const noexcept { return *_ptr; }
T& get() const noexcept { return *_ptr; }
private:
T* _ptr;
bool _copied;
};
Upon construction this class stores a pointer to it's argument, which is also modified when the copy assignment operator is used. But when an instance is copy constructed, then a heap allocated copy of the referenced (by the other) value is made. This way, it's possible to swap two referenced values with code similar to
Value a, b;
copyable_ref<Value> ref_a{a}, ref_b{b};
copyable_ref<Value> temp{ref_a};
ref_a = ref_b;
ref_b = temp;
// a and b are swapped
This was necessary because std::sort doesn't seem to use swap (found through ADL or std::swap) but code equivalent to the one above.
Now it's possible to sort a filtered "view" by filling a vector with (not copy constructed) instances of the weird wrapper class and sorting that vector. As the output in the example is showing, there's at most one heap allocated copy of a value type. Not counting the needed size for the pointers inside of the wrapper, this class enables filtered sorting with constant space overhead:
vector<int> input {1,2,3,4,5,6,7,8,9};
vector<copyable_ref<int>> sorted;
sorted.reserve(input.size());
for (auto & e : input) {
if (e % 2 != 0) {
sorted.emplace_back(e);
}
}
sort(begin(sorted), end(sorted),
greater<int>{});
copy(begin(input), end(input),
ostream_iterator<int>{cout, ", "});
cout << endl;
// 9 2 7 4 5 6 3 8 1
Finally, while this works quite well, I probably wouldn't use this in production code. I was especially surprised that std::sort wasn't using my own swap implementation, which led to this adventurous copy constructor.
You cannot generalise your code to work for sets and maps: Those are sorted by design, and they need that fixed order to function properly. And the unordered variants are, well, unordered and thus cannot maintain an order. But you can always (as long as you don't modify the container) use std::reference_wrappers inside of a vector to provide a sorted "view" of your data.
Based on Beta's idea to sort using iterators, though I'm not sure what the time-complexity is. It also does not work with all containers, e.g. std::set, std::map.
template <typename Container, typename Comparator, typename Predicate>
void sortButKeepSomeFixed (Container& c, const Comparator& comp, const Predicate& pred) {
std::vector<typename Container::value_type> toSort;
std::vector<typename Container::iterator> iterators;
for (typename Container::iterator it = c.begin(); it != c.end(); ++it) {
if (!pred(*it)) {
toSort.emplace_back(*it);
iterators.emplace_back(it);
}
}
std::sort(toSort.begin(), toSort.end(), comp);
for (std::size_t i = 0; i < toSort.size(); i++)
*iterators[i] = toSort[i];
}
std::vector<int> vector = {5,7,1,8,9,3,20,2,11};
std::array<int, 9> array = {5,7,1,8,9,3,20,2,11};
std::list<int> list = {5,7,1,8,9,3,20,2,11};
std::set<int> set = {5,7,1,8,9,3,20,2,11};
std::map<double, int> map = { {1.5,5}, {1.2,7}, {3.5,1}, {0.5,8}, {5.2,9}, {7.5,3}, {0.1,20}, {1.8,2}, {2.4,11} };
template <typename Container>
void test (Container& container) {
sortButKeepSomeFixed (container,
std::greater<int>(), // Ordering condition.
[](int x) {return x % 2 == 0;}); // Those that shall remain fixed.
for (int x : container) std::cout << x << ' ';
std::cout << '\n';
}
int main() {
test(vector); // 11 9 7 8 5 3 20 2 1
test(array); // 11 9 7 8 5 3 20 2 1
test(list); // 11 9 7 8 5 3 20 2 1
test(set); // Does not compile.
sortButKeepSomeFixed (map,
[](const std::pair<double, int>& x, const std::pair<double, int>& y) {return x.second > y.second;},
[](const std::pair<double, int>& x) {return x.second % 2 == 0;});
for (const std::pair<double, int>& x : map)
std::cout << "(" << x.first << "," << x.second << ") "; // Does not compile.
}
Error for set and map is "Assignment of read-only location".
Anyone know how to generalize this to work with sets and maps?
Update: So I suggest for set, maps, etc..., simply remove those elements that satisfy pred and the create a new set/map/... with Compare as their key_compare type. Like below. But it is only for set. How to generalize it to other containers that have key_compare types?
template <typename Container, typename Comparator, typename Predicate>
std::set<typename Container::value_type, Comparator, typename Container::allocator_type>
sortButRemoveSomeElements (Container& c, const Comparator&, const Predicate& pred) {
std::set<typename Container::value_type, Comparator, typename Container::allocator_type> set;
std::vector<typename Container::value_type> keep;
for (typename Container::iterator it = c.begin(); it != c.end(); ++it) {
if (!pred(*it))
keep.emplace_back(*it);
}
for (typename Container::value_type x : keep)
set.emplace(x); // Sorted by Comparator automatically due to std::set's insertion property.
return set;
}
The test:
struct GreaterThan { bool operator()(int x, int y) const {return x > y;} };
std::set<int, GreaterThan> newSet = sortButRemoveSomeElements (set,
GreaterThan{}, // Ordering condition.
[](int x) {return x % 2 == 0;}); // Those that shall be removed.
for (int x : newSet) std::cout << x << ' '; // 11 9 7 5 3 1
I am simply trying to add values of a map defined in the program below:
std::map<int, int> floor_plan;
const size_t distance = std::accumulate(std::begin(floor_plan), std::end(floor_plan), 0);
std::cout << "Total: " << distance;
I get the following error:
Error C2893: Failed to specialize function template 'unknown-type std::plus::operator ()(_Ty1 &&,_Ty2 &&) const'
std::begin(floor_plan) gives you an iterator pointing at std::map<int, int>::value_type which is std::pair<const int, int>. Since there is no operator+ defined for this pair type and an integer, your code fails to compile.
Option #1
If you want to sum up all the mapped values from floor_plan, you'd need to provide your own binary operator that is able to extract the second element of a dereferenced iterator passed in:
std::accumulate(std::begin(floor_plan)
, std::end(floor_plan)
, 0
, [] (int value, const std::map<int, int>::value_type& p)
{ return value + p.second; }
);
DEMO 1
Option #2
Alternatively, you could exploit the Boost.Iterator library to extract the second element of a pair on the fly with boost::make_transform_iterator:
#include <boost/iterator/transform_iterator.hpp>
#include <functional>
auto second = std::mem_fn(&std::map<int, int>::value_type::second);
std::accumulate(boost::make_transform_iterator(std::begin(floor_plan), second)
, boost::make_transform_iterator(std::end(floor_plan), second)
, 0);
DEMO 2
Option #3
Another approach is to use the Boost.Range library along with its own implementation of the accumulate algorithm:
#include <boost/range/numeric.hpp>
#include <boost/range/adaptor/map.hpp>
boost::accumulate(floor_plan | boost::adaptors::map_values, 0);
DEMO 3
Piotr S. answer is right, but if this is not a one-time task, you better make a simple convenient functor for such tasks:
struct AddValues
{
template<class Value, class Pair>
Value operator()(Value value, const Pair& pair) const
{
return value + pair.second;
}
};
const size_t distance = std::accumulate(plan.begin(), plan.end(), 0, AddValues());
Thank to templated operator() you can use this functor for any map in your code. This is much like transparent comparator, but this is transparent "summator".
I will show you not only how does it works.
accumulate Possible implementation as below(as we may sum from a base value, so there is a init value):
template<class InputIt, class T, class BinaryOperation>
T accumulate(InputIt first, InputIt last, T init,
BinaryOperation op)
{
for (; first != last; ++first) {
init = op(std::move(init), *first); // std::move since C++20
}
return init;
}
So when we wants to get sum/product of a vector, it may like this:
vector<int> vec(5);
std::iota(vec.begin(), vec.end(), 1);
cout<<"vec: ";// output vec
std::copy(vec.begin(), vec.end(), std::ostream_iterator<int>(cout, ", "));
// vec: 1, 2, 3, 4, 5,
cout<<"\n vec sum is: "<<accumulate(vec.begin(), vec.end(), 0)<<endl;
// vec sum is: 15
cout<<"vec product is: "<<accumulate(vec.begin(), vec.end(), 1, std::multiplies<int>())<<endl;
// vec product is: 120
As to std::map, you wants to sum the second value of an map, so you have to get each second item in map. So you should get the value_type in map and then get the second item. value_type in map is defined as below:
template <typename Key, typename Value, class Compare = std::less<Key>>
class map{
// using re_tree to sort
typedef Key key_type;
// rb_tree value type
typedef std::pair<key_type, value_type> value_type;
};
For example, get the sum of all the second/first value:
typedef map<string, int> IdPrice;
IdPrice idPrice = {{"001", 100}, {"002", 300}, {"003", 500}};
int sum = accumulate(idPrice.begin(), idPrice.end(), 0, [](int v, const IdPrice::value_type& pair){
return v + pair.second;
// if we want to sum the first item, change it to
// return v + pair.first;
});
cout<<"price sum is: "<<sum<<endl; // price sum is: 900
The para v in the above lambda funtion, stores the tmp sum, with init value 0.
Alternatively, you could use lambda expression with pair<int,int> as the binary operation.
distance = std::accumulate(std::begin(floor_plan), std::end(floor_plan), 0,
[](int value, pair<int,int> p) { return value + p.second; });
Here is a simple example :
#include <iostream>
#include <map>
#include <numeric>
int main() {
// Create a map with some initial key-value pairs
std::map<std::string, int> m = {{"a", 1}, {"b", 2}, {"c", 3}};
// Use std::accumulate to add up all of the values in the map
int sum = std::accumulate(m.begin(), m.end(), 0,
[](int total, const std::pair<std::string, int>& p) {
return total + p.second;
});
// Print the sum of the values in the map
std::cout << "The sum of the values in the map is " << sum << "\n";
return 0;
}
I have multimap:
multimap<string, vector<object> > myMultimap;
and I need to change string in part of multimap that has been already created.
it->first = newString;
doesn't work....
If you need to "change" the keys of all elements with that key:
template<typename Key, typename ValueType, typename Compare,
typename Allocator, typename FromKey, typename ToKey>
auto change_key(std::multimap<Key, ValueType, Compare, Allocator>& m,
FromKey const& from_raw, ToKey const& to_raw)
-> typename std::multimap<Key, ValueType, Compare, Allocator>::iterator
{
Key const& from = from_raw; // convert once only, not in each iteration
Key const& to = to_raw;
auto hint = m.lower_bound(to);
auto const itsFrom = m.equal_range(from);
for(auto cur = itsFrom.first; cur != itsFrom.second; ++cur)
{
hint = m.emplace_hint(hint, to, std::move(cur->second));
}
m.erase(itsFrom.first, itsFrom.second);
return hint;
}
In C++1y, if the comparison function object is transparent, you might want to drop the explicit conversion to from and to.
I'm not quite sure if I used lower_bound correctly as a hint; the Standard (n3797) says the following about the hint p in Table 102 - Associative container requirements (in addition to container):
The element is inserted as close as possible to the position just prior to p.
and the complexity:
logarithmic in general, but amortized constant if the element is inserted right before p
So we need the position after our insertion point; I'm not sure if the insertion point itself is a useful hint. To me, this seems to suggest using upper_bound, since that always returns a position with a key greater than the searched key; on the other hand I keep finding answers that suggest using lower_bound is the way to go.
Usage example:
#include <map>
#include <vector>
#include <iostream>
#include <string>
struct object
{
int m;
};
std::ostream& operator<<(std::ostream& o, object const& p)
{
return o << p.m;
}
template<typename V>
std::ostream& operator<<(std::ostream& o, std::vector<V> const& v)
{
for(auto const& e : v) o << e;
return o;
}
template<typename K, typename V>
std::ostream& operator<<(std::ostream& o, std::multimap<K, V> const& m)
{
for(auto const& p : m) o << "["<<p.first<<" : "<<p.second<<"], ";
return o;
}
int main()
{
auto make_vector = [](int p) { return std::vector<object>{{p}}; };
std::multimap<std::string, std::vector<object>> myMultimap =
{{
{"1st", make_vector(0)}
, {"1st", make_vector(1)}
, {"1st", make_vector(2)}
, {"2nd", make_vector(3)}
, {"2nd", make_vector(4)}
, {"2nd", make_vector(5)}
, {"3rd", make_vector(6)}
, {"3rd", make_vector(7)}
, {"3rd", make_vector(8)}
}};
std::cout << myMultimap;
change_key(myMultimap, "2nd", "4th");
std::cout << "\n\n" << myMultimap;
}
You can't change the key of the map/multimap, because it's a constant value. Another way is to find key you want replace, remove it and insert new value:
typedef multimap<string, vector<object> > Multimap;
Multimap myMultimap;
// ...
Multimap::iterator item_pos = myMultimap.find("some value");
if(item_pos != myMultimap.end())
{
vector<object> key_value = item_pos->second;
myMultimap.erase(item_pos);
myMultimap.insert(Multimap::value_type("new value", key_value));
}
You cannot just "change" a key like that, you have to create a new entry for the record, and erase the old one:
multimap<string, vector<object> > myMultimap;
...
myMultimap.insert(std::make_pair(newString, it->second));
myMultimap.erase(it);
Given:
"I have a multimap" and,
"I need to change the key and not the data"
The answer is:
"You have chosen the wrong data structure - it's time to rethink the solution"
Given a vector std::vector<double> v, we can find unique elements efficiently by:
std::vector<double> uv(v.begin(), v.end());
std::sort(uv.begin(), uv.end());
std::erase(std::unique(uv.begin, uv.end()), uv.end());
What would the be the nicest way (without loops, with STL or lambdas) to create a vector:
std::vector<double> freq_uv(uv.size());
which would contain frequencies of each distinct element appearing in v (order the same as sorted unique values)?
Note: type can be anything, not just double
After you sort, before you erase:
std::vector<int> freq_uv;
freq_uv.push_back(0);
auto prev = uv[0]; // you should ensure !uv.empty() if previous code did not already ensure it.
for (auto const & x : uv)
{
if (prev != x)
{
freq_uv.push_back(0);
prev = x;
}
++freq_uv.back();
}
Note that, while I generally like to count occurences with a map, as Yakk is doing, in this case I think it is doing a lot of unnecessary work as we already know the vector is sorted.
Another possibility is to use a std::map (not unordered), instead of sorting. This will get your frequencies first. Then, since the map is ordered, you can just create the sorted, unique vector, and the frequency vector directly from the map.
// uv not yet created
std::map<T, int> freq_map;
for (auto const & x : v)
++freq_map[x];
std::vector<T> uv;
std::vector<int> freq_uv;
for (auto const & p : freq_map)
{
uv.push_back(p.first);
freq_uv.push_back(p.second);
}
First, note that == and to a lesser extent < on double is often a poor idea: often you'll have values that logically "should" be equal if the double was infinite precision, but are slightly different.
However, collecting the frequencies is easy:
template<typename T, typename Allocator>
std::unordered_map< T, std::size_t > frequencies( std::vector<T, Allocator> const& src ) {
std::unordered_map< T, std::size_t > retval;
for (auto&& x:src)
++retval[x];
return retval;
}
assuming std::hash<T> is defined (which it is for double). If not, there is more boilerplate, so I'll skip it. Note that this does not care if the vector is sorted.
If you want it in the form of std::vector<std::size_t> in sync with your sorted vector, you can just do this:
template<typename T, typename Hash, typename Equality, typename Allocator>
std::vector<std::size_t> collate_frequencies(
std::vector<T, Allocator> const& order,
std::unordered_map<T, std::size_t, Hash, Equality> const& frequencies
) {
std::vector<std::size_t> retval;
retval.reserve(order.size());
for( auto&& x : order )
retval.push_back( frequencies[x] );
return retval;
}
I took the liberty of making these functions overly generic, so they support more than just doubles.
using equal_range:
std::vector<int> results;
for(auto i = begin(v); i != end(v);)
{
auto r = std::equal_range(i, end(v), *i);
results.emplace_back( std::distance(r.first, r.second) );
i = r.second;
}
SSCCE:
#include <vector>
#include <algorithm>
#include <iostream>
#include <iterator>
int main()
{
std::vector<double> v{1.0, 2.0, 1.0, 2.0, 1.0, 3.0};
std::sort(begin(v), end(v));
std::vector<int> results;
for(auto i = begin(v); i != end(v);)
{
auto r = std::equal_range(i, end(v), *i);
results.emplace_back( std::distance(r.first, r.second) );
i = r.second;
}
for(auto const& e : results) std::cout << e << "; ";
}
An O(n) solution when the range of values is limited, for example chars. Using less than the CPU level 1 cache for the counter leaves room for other values.
(untested code)
constexp int ProblemSize = 256;
using CountArray = std::array<int, ProblemSize>;
CountArray CountUnique(const std::vector<char>& vec) {
CountArray count;
for(const auto ch : vec)
count[ch]++;
return count;
}
Is there an stl way to get a list of values from a map?
i.e, I have:
std::map<A,B> myMap;
and I would like a function that will return just the list of values, i.e, std::list<B> (or set for that matter.
Is there a built-in stl way to do this?
A map element is defined as a map::value_type, and the type of it is a pair<A,B>. first is the key and second is the value. You can write a functor to extract second from a value_type, and copy that in to a vector (or a list, or whatever you want.) The best way to do the copying is to use transform, which does just what its name implies: it takes a value of one type and transforms it to a different type of value.
Here's a complete working example:
#include <cstdlib>
#include <map>
#include <string>
#include <algorithm>
#include <iterator>
#include <vector>
#include <iostream>
using namespace std;
typedef map<unsigned, string> MyMap;
MyMap my_map;
struct get_second : public std::unary_function<MyMap::value_type, string>
{
string operator()(const MyMap::value_type& value) const
{
return value.second;
}
};
int main()
{
my_map[1] = "one";
my_map[2] = "two";
my_map[3] = "three";
my_map[4] = "four";
my_map[5] = "five";
// get a vector of values
vector<string> my_vals;
transform(my_map.begin(), my_map.end(), back_inserter(my_vals), get_second() );
// dump the list
copy( my_vals.begin(), my_vals.end(), ostream_iterator<string>(cout, "\n"));
}
EDIT:
If you have a compiler that supports C++0x lambdas, you can eliminate the functor entirely. This is very useful for making code more readable and, arguable, easier to maintain since you don't end up with dozens of little one-off functors floating around in your codebase. Here's how you would change the code above to use a lambda:
transform(my_map.begin(), my_map.end(), back_inserter(my_vals), [](const MyMap::value_type& val){return val.second;} );
There's nothing built in, no. It's simple enough to write your own function, though: Iterate over the map. The iterator will give you a pair<A, B>. Add each second value to the result list.
You can't just "get" such a list because there is no pre-existing list stored anywhere in the guts, but you can build one:
typedef std::map<A,B> myMapType;
myMapType myMap;
std::list<B> valueList;
for (myMapType::const_iterator it=myMap.begin(); it!=myMap.end(); ++it) {
valueList.push_back( it->second );
}
Or if you really like the more STL way:
class GetSecond {
template<typename T1, typename T2>
const T2& operator()( const std::pair<T1,T2>& key_val ) const
{ return key_val.second; }
};
typedef std::map<A,B> myMapType;
myMapType myMap;
std::list<B> valueList;
std::transform(myMap.begin(), myMap.end(), std::back_inserter(valueList),
GetSecond());
One of many "built-in" ways is of course the most obvious one. Just iterate over all pair elements, which are ordered by key (pair::first), and add the value (pair::second) to a new container, which you can construct with the correct capacity to get rid of excess allocations during the iteration and adding.
Just a note: std::list is seldom the container you actually want to be using. Unless, of course, you really, really do need its specific features.
Sure.
std::list<B> list;
std::for_each(myMap.begin(), myMap.end(), [&](const std::pair<const A, B>& ref) {
list.push_back(ref.second);
});
If you don't have a C++0x compiler, first you have my sympathies, and second, you will need to build a quick function object for this purpose.
You can use boost's transform_iterator: http://www.boost.org/doc/libs/1_64_0/libs/iterator/doc/transform_iterator.html
struct GetSecond {
template <typename K, typename T>
const T& operator()(const std::pair<K, T> & p) const { return p.second; }
template <typename K, typename T>
T& operator()(std::pair<K, T> & p) const { return p.second; }
};
template <typename MapType>
auto begin_values(MapType& m) -> decltype(boost::make_transform_iterator(m.begin(), GetSecond())) {
return boost::make_transform_iterator(m.begin(), GetSecond());
}
template <typename MapType>
auto end_values(MapType& m) -> decltype(boost::make_transform_iterator(m.end(), GetSecond())) {
return boost::make_transform_iterator(m.end(), GetSecond());
}
template <typename MapType>
struct MapValues {
MapType & m;
MapValues(MapType & m) : m(m) {}
typedef decltype(begin_values(m)) iterator;
iterator begin() { return begin_values(m); }
iterator end() { return end_values(m); }
};
template <typename MapType>
MapValues<MapType> get_values(MapType & m) {
return MapValues<MapType>(m);
}
int main() {
std::map<int, double> m;
m[0] = 1.0;
m[10] = 2.0;
for (auto& x : get_values(m)) {
std::cout << x << ',';
x += 1;
}
std::cout << std::endl;
const std::map<int, double> mm = m;
for (auto& x : get_values(mm)) {
std::cout << x << ',';
}
std::cout << std::endl;
}