How can I modify values in a map using range based for loop?
You can turn auto
into auto&
if you want to mutate/modify the container, for instance:
#include <map>
#include <iostream>
int main()
{
std::map<int, int> foobar({{1,1}, {2,2}, {3,3}});
for(auto& p : foobar) {
++p.second;
std::cout << '{' << p.first << ", " << p.second << "} ";
}
std::cout << std::endl;
}
compiles ands outputs
{1, 2} {2, 3} {3, 4}
live example
Can't modify the value of a reference in Range based loop
You can't modify a reference to x
because it is const
. It is const because iterating a std::set
through loop gives only const values.
See solution with const_cast
example code at the end of my answer.
It is known that std::set
stores all entries in a sorted tree.
Now imagine if you can modify a variable when iterating a loop, it means that after modification sorted order of std::set
might be changed. But std::set
should always keep invariant of its tree, hence it can't allow to make any modifications thus gives only const
values when iterating.
If you need to really modify set entry then you have to take it from set, delete from set and that add again to set. Even if sorted order is not changed after your modification, still you need to reinsert into set.
But there is a hacky workaround - you can make your method delMinentry
as having const
modifier. Then all fields that it modifies should be marked as mutable
. Mutable fields allow modifications from const
methods. And std::set
allows to call const
methods when iterating.
There is one more workaround - you make delMinterm()
as const
method, but inside this method do const_cast<Term &>(*this).delMintermNonConst()
, in other words from const method you can call non-const method if you do const_cast
. Also you can do const cast directly on loop variable if you're sure what you do, in other words if you modify Term in such a way that std::set
sorted order is not changed:
for (auto &x : PI) {
const_cast<Term &>(x).delMinterm(i);
}
If delMinterm()
results in such modification of a Term after which order of std::set
may change then you can't do const_cast
in code above. In other words if after delMinterm your operator <
may give a different result between terms, then you can't do this const cast and you have to reinsert into set (delete Term and add again).
Also don't forget that after reinserting into set you have to redo set iteration loop again from start, because after change to inner structure you can't keep iterating loop running further, iterators are invalidated.
If set's order changes (hence you can't do const_cast
) then you have to re-insert values of set, do this by copying values to vector, modifying them through delMinterm(), copying back to set, like this:
std::vector<Term> scopy(PI.cbegin(), PI.cend());
for (auto & x: scopy)
x.delMinterm(i);
PI = std::set<Term>(scopy.cbegin(), scopy.cend());
How to use range-based for() loop with std::map?
Each element of the container is a map<K, V>::value_type
, which is a typedef
for std::pair<const K, V>
. Consequently, in C++17 or higher, you can write
for (auto& [key, value]: myMap) {
std::cout << key << " has value " << value << std::endl;
}
or as
for (const auto& [key, value]: myMap) {
std::cout << key << " has value " << value << std::endl;
}
if you don't plan on modifying the values.
In C++11 and C++14, you can use enhanced for
loops to extract out each pair on its own, then manually extract the keys and values:
for (const auto& kv : myMap) {
std::cout << kv.first << " has value " << kv.second << std::endl;
}
You could also consider marking the kv
variable const
if you want a read-only view of the values.
range-based for loop for private map values
I'm going to first answer this in c++14.
Here is a minimal mapping iteratoroid:
template<class F, class It>
struct iterator_mapped {
decltype(auto) operator*() const {
return f(*it);
}
iterator_mapped( F f_in, It it_in ):
f(std::move(f_in)),
it(std::move(it_in))
{}
iterator_mapped( iterator_mapped const& ) = default;
iterator_mapped( iterator_mapped && ) = default;
iterator_mapped& operator=( iterator_mapped const& ) = default;
iterator_mapped& operator=( iterator_mapped && ) = default;
iterator_mapped& operator++() {
++it;
return *this;
}
iterator_mapped operator++(int) {
auto copy = *this;
++*this;
return copy;
}
friend bool operator==( iterator_mapped const& lhs, iterator_mapped const& rhs ) {
return lhs.it == rhs.it;
}
friend bool operator!=( iterator_mapped const& lhs, iterator_mapped const& rhs ) {
return !(lhs==rhs);
}
private:
F f;
It it;
};
it is not technically an iterator, but it qualifies for for(:)
loops.
template<class It>
struct range_t {
It b, e;
It begin() const { return b; }
It end() const { return e; }
};
template<class It>
range_t<It> range( It b, It e ) {
return {std::move(b), std::move(e)};
}
the above is an absolutely minimal iterator range type that can be for(:)
iterated.
template<class F, class R>
auto map_range( F&& f, R& r ) {
using std::begin; using std::end;
auto b = begin(r);
auto e = end(r);
using it = iterator_mapped<std::decay_t<F>, decltype(b)>;
return range( it( f, b ), it( f, e ) );
}
note that R&
not R&&
; taking an rvalue for r
here is dangerous.
auto GetStringIterator() const
{
return map_range( [](auto&& pair)->decltype(auto){
return pair.second;
}, m_Items );
}
and done.
Converting this to c++11 is a pain. You have to toss around std::function
s in place of lambdas (or write function objects that do the task instead of a lambda), replace decltype(auto)
with auto
and trailing return types, give the exact type of auto&&
arguments to lambdas, etc. You end up with about 25%-50% more code, most of it obscure type chasing.
This is basically what boost::adaptors::map_values
does, but this is hand-rolled so you can understand how it works and don't have a boost dependency.
Updating class member values inside a range based for loop in C++
Your loop makes a copy of the element into m
every iteration. Your changes to m
will be to that copy. Make m
a reference to the element in the container instead:
for(auto& m : mList)
Iterate values of a map using range-based for loop
From C++20, you can use views::values to get at the values of a std::map
, or a vector<pair>
for that matter:
for (auto v : m | std::views::values) // m is some map
// ...
demo
You can similarly get at the keys with views::keys
.
Can C++11 and C++17 Range-Based For Loop iterate to a specific position instead of full range of the map?
You either need an external counter to make early exit, eg:
int n = 0;
for(auto&& [k, v] : map)
{
if(++n > 10) break;
std::cout << k << ": " << v << std::endl;
}
Or, if you are not afraid of copying the map, you can do:
auto copy = std::map<...>{map.begin(), std::next(map.begin(), 10)};
for(auto&& [k, v] : copy)
{
std::cout << k << ": " << v << std::endl;
}
Finally, if you can use C++20, then you can simply do this:
#include <ranges>
for(auto&& [k, v] : map | std::views::take(10))
{
std::cout << k << ": " << v << std::endl;
}
Can I easily iterate over the values of a map using a range-based for loop?
The magic lies with Boost.Range's map_values
adaptor:
#include <boost/range/adaptor/map.hpp>
for(auto&& i : foo | boost::adaptors::map_values){
i->bar();
}
And it's officially called a "range-based for loop", not a "foreach loop". :)
Setting vector elements in range-based for loop
Change this loop statement
for(auto n: *CTdata)
to
for(auto &n : *CTdata)
that is you have to use references to elements of the vector.
Related Topics
"Dereferencing Type-Punned Pointer Will Break Strict-Aliasing Rules" Warning
Benefits of Ternary Operator VS. If Statement
Destructors of Builtin Types (Int, Char etc..)
Create New C++ Object at Specific Memory Address
Loop Unrolling to Achieve Maximum Throughput with Ivy Bridge and Haswell
How to Call a Function by Its Name (Std::String) in C++
Tools to Find Included Headers Which Are Unused
How to Sort a Std::Map First by Value, Then by Key
Visual Studio 2015 Doesn't Have Cl.Exe
The Copy Constructor and Assignment Operator
Are Static Variables in a Base Class Shared by All Derived Classes
Nonfree Module Is Missing in Opencv 3.0
How to Get a Copy of the File Libstdc++.So.6.0.15
C++ Preprocessor: Avoid Code Repetition of Member Variable List