C++11 range-based for and map : readability [duplicate] - c++

This question already has answers here:
How to use range-based for() loop with std::map?
(5 answers)
Closed 9 years ago.
The new range-based for loops really improve readability and are really easy to use. However, consider the following :
map<Foo,Bar> FooAndAssociatedBars;
for (auto& FooAndAssociatedBar : FooAndAssociatedBars) {
FooAndAssociatedBar.first.doSth();
FooAndAssociatedBar.second.doSomeOtherThing();
}
It may be a detail but I find it would have been more readable if I could have done something like :
for ( (auto& foo, auto& bar) : FooAndAssociatedBars) {
foo.doSth();
bar.doSomeOtherThing();
}
Do you know an equivalent syntax ?
EDIT:
Good news: C++17 has a proposal that adresses this problem, called structured bindings (see 1). In C++17, you should be able to write:
tuple<T1,T2,T3> f(/*...*/) {
/*...*/
return {a,b,c};
}
auto [x,y,z] = f(); // x has type T1, y has type T2, z has type T3
which solves this readability problem

There is no such thing as you want. The closest is to declare variables inside the loop:
for (auto& FooAndAssociatedBar : FooAndAssociatedBars) {
auto& foo = FooAndAssociatedBar.first;
auto& bar = FooAndAssociatedBar.second;
// ...
}

Not a good idea. Sooner or later, you would want the same for a std::tuple, and compiler should be able to use std::get<> on the tuple automatically. In my opinion your approach is pleasing you at the moment only, and you would find problems with this approach (assume it is implemented that way).
Standard committee has designed range-based for-loop with deep consideration. It is way better than foreach loop in other languages, and it is way shorter. Couple it with auto& and you are done!

And of course, you always have the possibility to use lambdas.
std::map<int, const char*> m { { 4, "hello" }, { 11, "c++" } };
convenient_for_each(m, [](int a, const char* b) {
std::cout << b << a << std::endl;
});
convenient_for_each(m, [](std::pair<int, const char> p) {
std::cout << p.first << p.second << std::endl;
});
Or wrapped as macro (not recommended)
FOREACH((int a, const char* b), m, std::cout << a << b << std::endl);
FOREACH((std::pair<int, const char*> p), m, std::cout << p.first << p.second << std::endl);
(Hackish sample implementation at LWS)
Auto won't work though, I'm still waiting for polymorphic lambdas. My approach is theoretically able to handle tuples as well.

Related

C++ iterate primitive type container with ranged for

What would be a better way (performance) to iterate primitive type container with ranged for (for reading elements values) - read elements by ref or by value?
std::vector<int> v;
for (const auto e : v) { std::cout << e; }
or
for (const auto& e : v) { std::cout << e; }
There is:
Is it counter-productive to pass primitive types by reference?
Wondering if these 2 things (passing and iterating by ref and value) might be somehow related.
Another note:
I do recognize what is the difference between access by ref, const-ref and value as well as copying values - I only interested in what way would perform better for READ-ONLY.
For small, primitive types, if you don't want to modify the elements of the container, then it's really a matter of style, although for such 'read-only' access, you're probably safer using the by-value approach (which will actually prevent any unintended modification of the 'originals' - although a const qualifier on the reference will also prevent that).
However, if you do want to modify the contained elements, then you will need to iterate using a reference variable, as shown in the below code sample:
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v{ 1,2,3,4,5 };
for (auto e : v) ++e; // By value: takes copies
for (auto f : v) std::cout << f << " "; // Elements unchanged
std::cout << std::endl;
for (auto& e : v) ++e; // By reference: refers to actual elements
for (auto f : v) std::cout << f << " "; // Elements incremented
std::cout << std::endl;
// for (const auto& e : v) ++e; // const reference: Compiler error!
return 0;
}
I am not saying that this is the only correct approach, but it is a completely valid approach: Do not worry about performance when writing the code. Care about readability and keep performance for when you have something correct and working.
Taking this as premise my advice is the following:
Use this as default when you do not need to modify the containers elements:
for (const auto& e : v) {}
Only when for some reason you need a copy of the elements (but still do not want to modify the elements) use
void foo(int& x) {}
for (auto e : v) {
e += 5;
foo(e);
}
If you need to modify the elements use a reference:
for (auto& e : v) {}
Last but not least, once you have working correct code and you realized that this loop is a bottneck by measuring: Look at the assembly to see what is better.
However, consider that any non-trivial loop body is likely to outweigh the difference between copying a small type and taking a reference.
In theory, the object variable can potentially be more efficient because it doesn't involve indirection through a reference. However, at least in this simple example the reference version may be optimised to be identical with the object version, so it wouldn't necessarily matter in practice.
Wondering if these 2 things (passing and iterating by ref and value) might be somehow related.
Yes. Same rules of thumb apply to both cases. And in both cases it likely won't matter if everything is inlined by the optimiser.

Create a template to iterate map in C++11 like C++17's structured bindings

C++17 brought us a nicer way to iterate through map using the Structured binding, as shown in this example .
I am bound to use C++14 but have a lot of repeating code that iterates over maps.
In C++14 it looks like this:
for (auto const& item : myMap)
{
std::string key = x.first;
int value = x.second;
//Code...
}
Is there a way to create either a template / define / using / anything else that will allow me the convenience of iterating in this manner but still compile as a C++14 application?
for( auto const& [key, value] : myMap)
{
//Code...
}
You cannot initialize variables inside the range-based loop until C++20, so the best option, that I can see to use such macro:
#define STRUCTURED_BINDING(a, b, map_item) \
const auto &a = map_item.first; \
const auto &b = map_item.second;
So then in your code, you can write something like that:
for(const auto& item: a)
{
STRUCTURED_BINDING(fst, snd, item);
std::cout << fst << " " << snd << std::endl;
}
You can improve this macro to be used with tuple (get<0>, get<1>, ...), rewriting macro to use variadic arguments.
Maybe you can hack something here - but you'd better not.
While #Midren's suggestion will indeed work, I want to suggest that you not do this.
It's true that the C++14 loop is more verbose than in C++17. But - it is easy to understand and well-recognized. Introducing a macro, or a custom gadget - may save you a few characters, but will cost you in Readability and Maintainability. If your macro-based approach were to become very popular, then the readability would become a non-issue and the maintainability would be almost trivial (just making sure everyone uses the same gadget and not redefining it, in larger projects). But - that will never happen, since we already have C++17.
Instead, I would tweak the naming and perhaps spacing to improve clarity. For example, suppose it's a map of foo's to bar's:
for (auto const& foo_bar_pair : myMap) {
const auto& foo = foo_bar_pair.first;
const auto& bar = foo_bar_pair.second;
//Code with `foo` and `bar`
}

Iterative for loop and lambda function

I have the following code:
#include <iostream>
#include <algorithm>
struct Point
{
int x, y;
Point(int x, int y): x(x), y(y) {}
};
int main()
{
Point arr[] = {
Point(4,2), Point(0,3), Point(1,2)
};
std::sort(arr, arr+sizeof(arr)/sizeof(Point), [](Point a, Point b){return a.x<b.x;});
return 0;
}
Now, i am supposed to write iterative for loop (built in cpp for_each loop) which prints out all of the elements of the array, where, as a iteration variable we must use auto reference.
Now, this confuses me a bit, since i know this can be done without any iteration variables or something, like this:
std::for_each(arr,arr + sizeof(arr)/sizeof(Point), [](Point a){cout<<a.x<<a.y<<std::endl;}
Obviously, this is not what i am asked to do, so, since i never found myself using iteration variables when dealing with for_each loop, i'd like to find out how am i supposed to do that properly, especially considering the fact that i have to use auto reference. Any help appreciated!
If you're looking for a solution based on std::for_each, you can do the following.
std::for_each(std::begin(arr), std::end(arr),
[](auto& p){ cout << p.x << p.y << "\n"; });
// ^^^^^ auto reference
Here, you have an auto& reference for the object that you intend to do something with in each iteration (in the case above, it would make sense to use const auto&).
This is almost identical to the range-based for loop suggested by #cdhowie. The only interesting point to note here is that std::for_each is one of the few (the only?) exception to the rule that callables passed to STL algorithms must not have side effects. In this case, writing to the global std::cout object is a side effect, and std::for_each explicitly allows that.
You're probably looking for the range-for loop:
for (auto & i : arr) {
std::cout << i.x << ',' << i.y << '\n';
}

What are use cases for structured bindings?

C++17 standard introduces a new structured bindings feature, which was initially proposed in 2015 and whose syntactic appearance was widely discussed later.
Some uses for them come to mind as soon as you look through documentation.
Aggregates decomposition
Let's declare a tuple:
std::tuple<int, std::string> t(42, "foo");
Named elementwise copies may be easily obtained with structured bindings in one line:
auto [i, s] = t;
which is equivalent to:
auto i = std::get<0>(t);
auto s = std::get<1>(t);
or
int i;
std::string s;
std::tie(i, s) = t;
References to tuple elements can also be obtained painlessly:
auto& [ir, sr] = t;
const auto& [icr, scr] = t;
So we can do with arrays or structs/classes whose all members are public.
Multiple return values
A convenient way to get multiple return values from a function immediately follows from the above.
What else?
Can you provide some other, possibly less obvious use cases for structured bindings? How else can they improve readability or even performance of C++ code?
Notes
As it were mentioned in comments, current implementation of structured bindings lacks some features. They are non-variadic and their syntax does not allow to skip aggregate members explicitly. Here one can find a discussion about variadicity.
Can you provide some other, possibly less obvious use cases for structured bindings? How else can they improve readability or even performance of C++ code?
More in general, you can use it to (let me say) unpack a structure and fill a set of variables out of it:
struct S { int x = 0; int y = 1; };
int main() {
S s{};
auto [ x, y ] = s;
(void)x, void(y);
}
The other way around would have been:
struct S { int x = 0; int y = 1; };
int main() {
S s{};
auto x = s.x;
auto y = s.y;
(void)x, void(y);
}
The same is possible with arrays:
int main() {
const int a[2] = { 0, 1 };
auto [ x, y ] = a;
(void)x, void(y);
}
Anyway, for it works also when you return the structure or the array from a function, probably you can argue that these examples belong to the same set of cases you already mentioned.
Another good example mentioned in the comments to the answer by #TobiasRibizel is the possibility to iterate through containers and unpack easily the contents.
As an example based on std::map:
#include <map>
#include <iostream>
int main() {
std::map<int, int> m = {{ 0, 1 }, { 2, 3 }};
for(auto &[key, value]: m) {
std::cout << key << ": " << value << std::endl;
}
}
Can you provide some other, possibly less obvious use cases for structured bindings?
They can be used to implement get<N> for structs - see magic_get's automatically generated core17_generated.hpp. This is useful because it provides a primitive form of static reflection (e.g. iterate over all members of a struct).
Initializing multiple variables of different types in an if statement; for instance,
if (auto&& [a, b] = std::pair { std::string { "how" }, 4U }; a.length() < b)
std::cout << (a += " convenient!") << '\n';
Barring evidence to the contrary, I think Structured Bindings are merely a vehicle to deal with legacy API. IMHO, the APIs which require SB should have been fixed instead.
So, instead of
auto p = map.equal_range(k);
for (auto it = p.first; it != p.second; ++it)
doSomethingWith(it->first, it->second);
we should be able to write
for (auto &e : map.equal_range(k))
doSomethingWith(e.key, e.value);
Instead of
auto r = map.insert({k, v});
if (!r.second)
*r.first = v;
we should be able to write
auto r = map.insert({k, v});
if (!r)
r = v;
etc.
Sure, someone will find a clever use at some point, but to me, after a year of knowing about them, they are still an unsolved mystery. Esp. since the paper is co-authored by Bjarne, who's not usually known for introducing features that have such a narrow applicability.

Is this a legitimate way to find the position of an element in a vector? [duplicate]

This question already has answers here:
Obtaining item index in ranged based for on vector
(2 answers)
Closed 5 years ago.
I have the following loop in my code:
for (const auto& item : vec) {...}
In order to find the position of item in vec, I do:
size_t pos = ((size_t)&item-(size_t)vec.data())/sizeof(item);
But it feels kinda "C" (in opposed to "C++").
I know that I can achieve this purpose if I change my loop-format to either one of the following:
for (size_t i = 0; i < vec.size(); i++) {...}
for (auto it = vec.begin(); it != vec.end(); it++) {...}
But I would like to refrain from doing this.
Bottom line questions:
Is my method guaranteed by the language standard?
Is there a more "C++" way to do this without changing the loop-format?
Thank you.
But I would like to refrain from doing this.
Looping over an index/iterator is the exact thing you need here. Why would you refrain from doing that?
Is my method guaranteed by the language standard?
Just the fact that you have to ask this question to makes your method undesirable compared to a index/iterator loop. Regardless, I cannot see any reason why your method should fail.
Is there a more "C++" way to do this without changing the loop-format?
The most idiomatic C++ way is looping over an index/iterator. If you want a fancier version of that, you can wrap the logic in an higher-order function that provides the item as well:
template <typename Container, typename F>
void for_each_with_index(Container&& c, F&& f)
{
for(std::size_t i = 0; i < c.size(); ++i)
{
f(c[i], i);
}
}
Usage:
std::vector<item> v{/* ... */};
for_each_with_index(v, [](auto& item, std::size_t index)
{
/* ... */
});
live example on wandbox
You don't need to cast your types as you did in your example:
size_t pos = ((size_t)&item-(size_t)vec.data())/sizeof(item);
You can do pointer arithmetics more simplier as follows:
#include <iostream>
#include <vector>
int main() {
std::vector<int> test { 0, 1, 2, 3, 4, 5, 6 };
for(const auto& elem : test) {
const auto pos = &elem - test.data();
std::cout << "Element at position " << pos << " is: " << elem << std::endl;
}
return 0;
}
The reason it works because the type of &elem is const int* and the returning type of test.data() is int* so the pointer arithmetics works fine on them.
Note: if you forget the reference operator (&) in you range-based for loop the example above won't work:
for(const auto elem : test) { /* ... */ } // Warning: elem is a copy!
If you are really dying to do this in C++ without changing the loop format substantially, considering incorporating cpp itertools: https://github.com/ryanhaining/cppitertools/blob/master/README.md. It's your only hope!
vector<int> vec{2, 4, 6, 8};
for (auto&& e : enumerate(vec)) {
cout << e.index
<< ": "
<< e.element
<< '\n';
}
It provides lots more tools, drawing inspiration from python which is known for having very nice ways of iterating. You can also iterate over two same size vectors together, de-nest nested for loops, etc.
Strictly speaking, you can also implement enumerate yourself. It's not that difficult but it is quite a few lines of boilerplate.