Yes, it is, there is no restriction about it. In C++ is also very common creating for loops with iterators.
Use the range-based for statement to construct loops that must execute through a range, which is defined as anything that you can iterate through—for example, std::vector , or any other C++ Standard Library sequence whose range is defined by a begin() and end() .
You can't. The index is a specific notion to a vector, and not a generic property of a collection. The range-based loop on the other hand is a generic mechanism for iterating over every element of any collection.
If you do want to use the details of your particular container implementation, just use an ordinary loop:
for (std::size_t i = 0, e = v.size(); i != e; ++i) { /* ... */ }
To repeat the point: Range-based loops are for manipulating each element of any collection, where the collection itself doesn't matter, and the container is never mentioned inside the loop body. It's just another tool in your toolbox, and you're not forced to use it for absolutely everything. By contrast, if you either want to mutate the collection (e.g. remove or shuffle elements), or use specific information about the structure of the collection, use an ordinary loop.
I created a preprocessor macro (greatly simplified by @Artyer) that handles this for you in a relatively clean way:
#define for_indexed(...) for_indexed_v(i, __VA_ARGS__)
#define for_indexed_v(v, ...) if (std::size_t v = -1) for (__VA_ARGS__) if ((++v, true))
Example usage:
std::vector<int> v{1, 2, 3};
for_indexed (auto const& item : v) {
if (i > 0) std::cout << ", ";
std::cout << i << ": " << item;
}
To use a different loop variable:
for_indexed_v (my_counter, auto const& item : v) ...
The extra control flow logic should be optimized away in any non-debug builds. You're left with a relatively easy-to-read loop syntax.
2020 note: It would probably be more wise to use a lambda-based solution instead of macro trickery. Of course, the syntax wouldn't be as "clean", but it would have the advantage of being recognizable as actual C++ syntax. The choice is yours.
Update 2017/05/28: Made break;
statements work correctly
Update 2019/01/28: Put for
in the macro name so that the word indexed
is a valid variable name. I doubt for_indexed
will cause any conflicts.
Update 2020/12/23: Simplified drastically (thanks @Artyer)
You can use the enumerate
view of range-v3:
std::vector<thisObject> storedValues;
for (auto const& [idx, value] : storedValues | ranges::views::enumerate) {
std::cout << idx << ": " << value << '\n';
}
C++20 will introduce additional initializations in range-for loops:
std::vector<thisObject> storedValues;
for (size_t idx = 0; auto value : storedValues) {
std::cout << idx << ": " << value << '\n';
++idx;
}
Use range-v3
. Range-v3
is the next generation range library designed and implemented by ISO C++ Committee member Eric Niebler, and is intended and expected to be merged in the C++ standard in the future.
By Using range-v3
OP's problem can be solved easily:
using ranges::v3::view::zip;
using ranges::v3::view::ints;
for(auto &&[i, idx]: zip(storedValues, ints(0u))){
std::cout << idx << ": " << i.function() << '\n';
}
You will need a compiler that support C++17 or later to compile this piece of code, not only for the structured binding syntax, but also for the fact that the return type of begin
and end
function for the return value of ranges::v3::view::zip
differ.
You can see the online example here. The documentation of range-v3
is here and the source code itself is hosted here. You can also have a look at here if you are using MSVC compilers.
It's pretty simple honestly, just got to figure out that you can subtract addresses :)
&i will reference the address in memory, and it will increment by 4 from index to index because it's hold a integer from the defined vector type. Now &values[0] references the first point, when you subtract the 2 addresses, the difference between the two will be 0,4,8,12 respectfully, but in reality its subtracting the size of the integer type which is usually 4 bytes. So in correspondence 0 = 0th int,4 = 1st int, 8 = 2nd int, 12 = 3rd int
Here it is in a vector
vector<int> values = {10,30,9,8};
for(auto &i: values) {
cout << "index: " << &i - &values[0];
cout << "\tvalue: " << i << endl;
}
Here it is for a regular array, pretty much the same thing
int values[]= {10,30,9,8};
for(auto &i: values) {
cout << "index: " << &i - &values[0];
cout << "\tvalue: " << i << endl;
}
Note this is for C++11, if you're using g++, remember to use -std=c++11 parameter for compiling
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With