Shorthand for for-loop - syntactic sugar in C++(11) - c++

Actually these are two related questions.
I know there is a new syntax in C++11 for range-based for loops of the form:
//v is some container
for (auto &i: v){
// Do something with i
}
First question: how can I infer at which iteration I am in this loop? (Say I want to fill a vector with value j at position j).
Second question: I wanted to know if there also is some other way to write a loop of the form
for (int i=0; i<100; i++) { ... }
I find this way of writing it a bit cumbersome, and I do this so often and I would love to have a more concise syntax for it.
Something along the lines:
for(i in [0..99]){ ... }
would be great.
For both questions I would like to avoid having to use additional libraries.

First answer: you don't. You've used a simple construct for a simple purpose; you'll need something more complicated if you have more complicated needs.
Second answer: You could make an iterator type that yields consecutive integer values, and a "container" type that gives a range of those. Unless you have a good reason to do it yourself, Boost has such a thing:
#include <boost/range/irange.hpp>
for (int i : boost::irange(0,100)) {
// i goes from 0 to 99 inclusive
}

Use this:
size_t pos = 0;
for (auto& i : v) {
i = pos;
++pos;
}
(Boost is good, but it is not universally accepted.)

For the first question, the answer is pretty simple: if you need the iteration count, don't use the syntactic construct which abstracts away the iteration count. Just use a normal for loop and not the range-based one.
For the second question, I don't think there's anything currently in the standard library, but you could use a boost::irange for it:
for (int i : boost::irange(0, 100))

For the second question - if Boost is too heavy, you could always use this library:
cppitertools
for(auto i : range(10, 15)) { cout << i << '\n'; } will print 10 11 12 13 14
for(auto i : range(20, 30, 2)) { cout << i << '\n'; } will print 20 22 24 26 28
Doubles and other numeric types are supported too.
It has other pythonic iteration tools and is header-only.

You can do both of these things with Boost.Range: http://boost.org/libs/range
boost::adaptors::indexed: element value & index
boost::irange: integer range
For brevity (and to spice things up a little, since boost::irange has been already demonstrated in isolation), here's a sample code demonstrating these features working together:
// boost::adaptors::indexed
// http://www.boost.org/doc/libs/master/libs/range/doc/html/range/reference/adaptors/reference/indexed.html
#include <boost/range/adaptor/indexed.hpp>
// boost::irange
// http://www.boost.org/doc/libs/master/libs/range/doc/html/range/reference/ranges/irange.html
#include <boost/range/irange.hpp>
#include <iostream>
#include <vector>
int main()
{
std::vector<int> input{11, 22, 33, 44, 55};
std::cout << "boost::adaptors::indexed" << '\n';
for (const auto & element : input | boost::adaptors::indexed())
{
std::cout << "Value = " << element.value()
<< " Index = " << element.index()
<< '\n';
}
endl(std::cout);
std::cout << "boost::irange" << '\n';
for (const auto & element : boost::irange(0, 5) | boost::adaptors::indexed(100))
{
std::cout << "Value = " << element.value()
<< " Index = " << element.index()
<< '\n';
}
return 0;
}
Sample output:
boost::adaptors::indexed
Value = 11 Index = 0
Value = 22 Index = 1
Value = 33 Index = 2
Value = 44 Index = 3
Value = 55 Index = 4
boost::irange
Value = 0 Index = 100
Value = 1 Index = 101
Value = 2 Index = 102
Value = 3 Index = 103
Value = 4 Index = 104

If v is a vector (or any std contiguous container), then
for(auto& x : v ) {
size_t i = &x-v.data();
x = i;
}
will set the ith entry to the value i.
An output iterator that counts is reasonably easy to write. Boost has one and has an easy-to-generate range of them called irange.
Extracting the indexes of a container is relatively easy. I have written a function called indexes that can take a container, or a range of integers, and produces random output iterators over the range in question.
That gives you:
for (size_t i : indexes(v) ) {
v[i] = i;
}
There probably is an equivalent container-to-index range function in Boost.
If you need both, and you don't want to do the work, you can write a zipper.
for( auto z : zip( v, indexes(v) ) ) {
auto& x = std::get<0>(z);
size_t i = std::get<1>(z);
x = i;
}
where zip takes two or more iterable ranges (or containers) and produces a range view over tuples of iterator_traits<It>::references to the elements.
Here is Boost zip iterator: http://www.boost.org/doc/libs/1_41_0/libs/iterator/doc/zip_iterator.html -- odds are there is a Boost zip range that handles syntax like the above zip function.

For the 2nd question:
There is another way, but I would not use or recommend it. However, for quickly setting up a test you could write:
if you do not want to use a library and you are fine with only providing the top bound of the range you can write:
for (auto i:vector<bool>(10)) {
cout << "x";
}
This will create a boolean vector of size 10, with uninitialized values. Looping through these unitialized values using i (so do not use i) it will print 10 times "x".

For the second question, if you are using the latest Visual Studio versions, type 'if' then Tab, Tab, and Tab to fill in init value, step-up and so on.

Related

Range transformations with stateful lambdas and std::views::drop

it's my first time digging into the new <ranges> library and I tried a little experiment combining std::views::transform with a stateful lambda and 'piping' the resulting range to std::views::drop:
#include <iostream>
#include <ranges>
#include <vector>
using namespace std;
int main() {
auto aggregator = [sum = 0](int val) mutable
{
return sum += val;
};
vector<int> data{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
cout << "Expected:\n";
int sum = 0;
for (int val : data) {
cout << (sum += val) << ' ';
}
cout << '\n';
cout << "Transformation:\n- - - ";
for (int val : data | views::transform(aggregator) | views::drop(3)) {
cout << val << ' ';
}
cout << '\n';
}
The output was:
Expected:
1 3 6 10 15 21 28 36 45 55
Transformation:
- - - 4 9 15 22 30 39 49
Now, the difference between each expected and actual output is 1 + 2 + 3 = 6. I am guessing it is a result of the lazy evaluation of ranges that causes std::views::drop to disregard the first three transformations.
Is there a way for me to force the evaluation of the aggregator functor for the three elements I drop? Or are stateful lambdas and ranges considered incompatible?
transform_view is required to be a pure function. This is codified in the regular_invocable concept:
The invoke function call expression shall be equality-preserving and shall not modify the function object or the arguments.
This is important to allow transform_view to not lie about its iterator status. Forward iterators, for example, are supposed to allow multipass iteration. This means that the value at each iterator position within the range must be independent of any other iterator position. That's not possible if the transformation functor is not pure.
Note that all predicate functors are also regular_invocable. So this also applies to things like filter_view and take_while_view.
Note that the algorithm transform does not have this requirement.

Is it possible to use a dynamic number of range adaptors?

I am fairly new to ranges, and I wanted to know if there was a way to apply a dynamic number of range adaptors. I have fiddled around with some code for a while, and I have also done some searching, but to no avail.
#include <iostream>
#include <ranges>
int main() {
auto output = std::ranges::views::iota(2, 100);
for (int i = 2; i < 100; i++) {
output = output | std::ranges::views::filter([i](int num){ return num % i != 0 || num == i; });
}
std::cout << "The 10th prime is: " << output[9] << "\n";
}
Essentially, I want something like this, but this gives a compile error (no match for 'operator='). It seems that each application of a range adaptor requires a new type, so we can't dynamically create this range. Is there some way around this?
For a fixed number like this, it would be possible to use metaprogramming to recursively build the range (although you might hit a template instantiation depth limit). You can do a truly dynamic number by type-erasing the ranges, such that the chain of filters is connected by virtual function calls. The result is slow and the code is painful, but it’s certainly possible.
One of the alternatives is to store the results of each filtering in a vector, which ensures that the range type after each operation is consistent and can be re-assigned.
#include <iostream>
#include <ranges>
#include <vector>
auto to_vector(std::ranges::view auto view) {
return std::vector(view.begin(), view.end());
}
int main() {
auto output = to_vector(std::views::iota(2, 100));
for (int i = 2; i < 100; i++) {
output = to_vector(output | std::views::filter(
[i](int num){ return num % i != 0 || num == i; }));
}
std::cout << "The 10th prime is: " << output[9] << "\n";
}
Demo.
However, this is inefficient and not a good use case for using range adaptors. So you may need to use more efficient algorithms to implement this.
In this particular case you can build the filter predicate instead:
int main() {
auto output = std::views::iota(2, 100);
std::function<bool(int)> filter_fn = [] (int) { return true; };
for (int i = 2; i < 100; i++)
{
filter_fn = [=] (int num) {
return filter_fn(num) && (num % i != 0 || num == i);
};
}
auto primes = output | std::views::filter(filter_fn);
std::cout << "The 10th prime is: " <<
(primes | std::views::drop(9)).front() << "\n";
}
Can doesn't mean should though. This is pretty inefficient as it creates a chain of indirect calls for the predicate.

Why does the simple arithmetic subtraction not work in the "if" condition?

I have 2 arrays with elements in them. I used hashing to get the frequencies of each element which occurs more than one time. mapcheckA contains the frequencies of elements of first array and mapcheckB contains the frequencies of the other array. I am trying to delete/erase any duplicates of elements from both the unordered maps. Here is the code that does it:
for (auto i : mapcheckA) {
if (mapcheckB.find(i.first) != mapcheckB.end()) {
if (i.second >=
mapcheckB.find(i.first)
->second) { // This block of code doesn't work as expected
i.second -= mapcheckB.find(i.first)->second;
mapcheckB.erase(i.first);
} else {
mapcheckB.find(i.first)->second -= i.second;
mapcheckA.erase(i.first);
}
}
}
for (auto i1 : mapcheckA) {
cout << i1.first << "\t" << i1.second << endl;
}
for (auto i : mapcheckB) {
cout << i.first << "\t" << i.second << endl;
}
When I enter elements in such a way that first array contains element with more frequency than in the second array, like this:
arrayA = [ 1, 1, 1, 1, 4, 4 ]; // Here frequency of "1" is 4.
arrayB = [ 2, 2, 1, 1, 3, 3 ]; // Here frequency of "1" is 2.
In this situation the block of code in the "if" condition does not change the frequency of 1 to 2.
If I change the order of arrays, then the code works fine. What am I doing wrong here?
You have two significant bugs:
working on a copy of the data (already identified in comments). Working with a reference means changes will be reflected in original container, rather than discarded when the copy goes out of scope.
for (auto& i : mapcheckA) { // add the &
undefined behavior
In your "else" case, you remove the element that is current in the iteration, invalidating iterator i, but the loop continues to increment i. Program state is indeterminate and this must not be done.
Unfortunately, with a ranged for loop, there is no good way to do this. Your options:
remember the key (or iterator) for later, and remove them after the loop
hand roll the loop for manual iterator incremeting:
for (auto i = begin(mappedA), e = end(mappedA); i != e; ) {
if (...) {
...
++i;
}
else {
...
i = mappedA.erase(i);
}
}
Further aside, you might consider using c++ structured bindings to make the code more readable and do fewer of the same lookups. Putting that all together:
for (auto iterA = begin(mapcheckA), endA = end(mapcheckA); iterA != endA; ) {
auto& [keyA, valueA] = *iterA;
if (auto iterB = mapcheckB.find(keyA); iterB != end(mapcheckB)) {
auto& [keyB, valueB] = *iterB;
if (valueA >= valueB) {
valueA -= valueB;
mapcheckB.erase(iterB);
++iterA;
} else {
valueB -= valueA;
iterA = mapcheckA.erase(iterA);
}
}
}
Note: both halves of the if update the iterA rather than doing it in the for-loop, since one uses ++ and the other takes the result of calling erase.

How does std::find auto-magically knows the end of an array in C++?

Why there is an atomic variable in the code below? - because it is part of a larger code base where the m_subscriptions array is being updated from multiple threads. Please bear with me on that one ..
Here is my question:
#include <iostream>
#include <atomic>
#include <algorithm>
#include <iterator>
#define MAX_SUBSCRIPTIONS 45
static std::atomic<int> numberOfSubscriptions;
int main ()
{
int m_subscriptions[MAX_SUBSCRIPTIONS] = {};
numberOfSubscriptions.fetch_add(0, std::memory_order_relaxed);
m_subscriptions[numberOfSubscriptions] = 12;
numberOfSubscriptions.fetch_add(1);
m_subscriptions[numberOfSubscriptions] = 13;
numberOfSubscriptions.fetch_add(1);
m_subscriptions[numberOfSubscriptions] = 14;
numberOfSubscriptions.fetch_add(1);
m_subscriptions[numberOfSubscriptions] = 15;
numberOfSubscriptions.fetch_add(1);
m_subscriptions[numberOfSubscriptions] = 16;
numberOfSubscriptions.fetch_add(1);
for ( int i = 0; i < numberOfSubscriptions; i++ )
std::cout << m_subscriptions[ i ] << "\t ";
std::cout << std::endl;
auto result = std::find(m_subscriptions, m_subscriptions + numberOfSubscriptions, 44);
if ( result == std::end(m_subscriptions) )
std::cout << "Not Found" << std::endl;
else
std::cout << *result << std::endl;
}
does not print "Not Found" when I pass something that is not present in the array.
If I replace if ( result == std::end(m_subscriptions) ) with
if ( result == (m_subscriptions + numberOfSubscriptions) )
it works !
HOW ??
How does std::find come to know how many values in m_subscriptions have been initialized ? Should it not go on till the end i.e. m_subscriptions[MAX_SUBSCRIPTIONS] like one would expect a dumb computer to ?
In other words, why does std::find stop searching for 44 at m_subscriptions + numberOfSubscriptions? Why does it not go on till m_subscriptions[MAX_SUBSCRIPTIONS] ?
std::find has no knowledge of the array or the elements that are initialised within it. You told it where to stop with the second argument:
std::find(m_subscriptions, // Start here
m_subscriptions + numberOfSubscriptions, // Stop here
44); // Try to find this
If it doesn't find what you're looking for, it just returns that second argument back, which is the end of the range that you gave it.
If you had passed std::end(m_subscriptions) as the second argument, it would have iterated over all the elements that you haven't assigned to. However, it's wroth noting that these aren't uninitialised, they have been value initialised. When you do aggregate initialisation with {}, any members of the aggregate that you haven't specified are value initialised. Regardless, even if they were uninitialised, there's no way to tell whether something has been initialised or not.
std::find needs the end iterator, and points to it where element not found
m_subscriptions + numberOfSubscriptions points to last element added
whereas std::end(m_subscriptions) points to pass the total capacity (45)
Try printing these :
std::cout << result - m_subscriptions ; // 5 with search element not in list
std::cout << std::end(m_subscriptions) - m_subscriptions ; //45

STL algorithm to generate Fibonacci numbers until a certain value is reached

The following code will generate the first 10 Fibonacci numbers using the adjacent_difference algorithm:
v = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
std::adjacent_difference(v.begin(), v.end() - 1, v.begin() + 1, std::plus<int>());
for (auto n : v) {
std::cout << n << ' ';
}
std::cout << '\n';
Output: 1 1 2 3 5 8 13 21 34 55
But what if I want to continue generating Fibonacci numbers until one with a value of (say) 4,000,000 is reached (e.g. not the fourth millionth Fibonacci number, but rather the Nth Fibonacci number whose value happens to be 4 million (or greater)).
Obviously a do while loop with a push_back would do the job, but I was wondering if it were possible to combine an STL algorithm with a back_inserter and lambda function to specify the repeat until condition (e.g. stop inserting after value 4 million is reached or exceeded)?
The problem I see is that most algorithms operate on a range, and ahead of time we do not know how many elements will be required to produce the Fibonacci number with 4 million.
Standard algorithms are there to extract implementations that are common in programming practice. This makes it easier both for you to understand the code and for the reader to understand it. Using built-in algorithms to accumulate the fibonnacci numbers up to a given value is an overkill both for you and for whoever reads your code.
Writing a 'dumb' solution for your usecase is really easy and will be easier to maintain. For instance:
void fibUpTo(int limit) {
int a, b, c;
a = b = 1;
while (a < limit) {
cout << a << endl;
c = a + b;
a = b;
b = c;
}
}
int my_plus(int a, int b)
{
int result = a + b;
if (result >= 4000000)
throw result;
return result;
}
try {
adjacent_difference(v.begin(), v.end() - 1, v.begin() + 1, my_plus);
} catch (int final) {
cout << final << endl;
}
That's what I'd consider a "dumb hack," but I think it will work. If you want to pretty it up a little, make an exception class to hold the final result instead of throwing a raw integer. And make the threshold a template parameter.
But really, don't do any of this, because it's a dumb hack: just use a "for" loop as you mentioned.
With find_if and a little help from boost iterator lib:
#include <boost/iterator/function_input_iterator.hpp>
#include <algorithm>
#include <climits>
struct fibonacci_generator {
typedef int result_type;
fibonacci_generator() : n(0) {}
// dummy generator
// put the code to generate fibonacci
// sequence here
int operator()() { return n++; }
private:
int n;
};
int main()
{
fibonacci_generator g;
int i = *std::find_if(
make_function_input_iterator(g, boost::infinite()),
make_function_input_iterator(g, boost::infinite()),
[](int i) { return i > 1000000; });
}
A copy_until algorithm could be useful here to push back results to a vector, but you need to write your own.