Reputation: 1360
in c++ 11 if we have a set<int> S
; we could say:
for (auto i: S)
cout << i << endl;
but can we force i
to be a iterator, I mean write a code that is equivalent to:
for (auto i = S.begin(); i != S.end(); i++)
cout << (i != s.begin()) ? " " : "" << *i;
or could we do something that we can understand the index of i
in the set(or vector)?
and another question is how could we say that don't do this for all elements in S
but for first half of them or all of them except the first one.
or when we have a vector<int> V
, and want to print its first n
values what should we do? I know we can create a new vector but it takes time to copy a vector to a new vector.
Upvotes: 10
Views: 22973
Reputation: 154035
Range-based for
is intended for simple cases. I'd expect to to mildly useful while protoyping something but would expect uses of it mostly gone long before things actually become a product. It may possibly useful to make life for beginners easier, but this is an area I can't judge (but what seems to drive a lot of the recent C++ discussions).
The only somewhat constructive approach could be to use an adapter which references the underlying range and whose begin()
and end()
methods adjust the iterator appropriately. Also note that you probably want to hoist any special handling of the first or last element out of the loop processing the bulk of the data. Sure, it is only another check followed by a correctly predicted branch vs. no check and less pollution of the branch prediction tables.
Upvotes: 1
Reputation: 70206
No, unluckily. See what the standard says:
The range-based for statement for ( for-range-declaration : expression ) statement is equivalent to
{ auto && __range = ( expression ); for ( auto __begin = begin-expr, __end = end-expr; __begin != __end; ++__begin ) { for-range-declaration = *__begin; statement } }
where __range, __begin, and __end are variables defined for exposition only
In other words, it already iterates from begin
to end
and already dereferences the iterator, which you never get to see.
Upvotes: 20
Reputation: 300349
The principle of the range-based for
is to iterate over the whole range.
However you decide what the range is, therefore you can operate on the range itself.
template <typename It>
class RangeView {
public:
typedef It iterator;
RangeView(): _begin(), _end() {}
RangeView(iterator begin, iterator end): _begin(begin), _end(end) {}
iterator begin() const { return _begin; }
iterator end() const { return _end; }
private:
iterator _begin;
iterator _end;
};
template <typename C>
RangeView<typename C::iterator> rangeView(C& c, size_t begin, size_t end) {
return RangeView<typename C::iterator>(
std::next(c.begin(), begin),
std::next(c.begin(), end)
);
}
template <typename C>
RangeView<typename C::const_iterator> rangeView(C const& c, size_t begin, size_t end) {
return RangeView<typename C::const_iterator>(
std::next(c.begin(), begin),
std::next(c.begin(), end)
);
}
Okay, this seriously ressemble Boost.Range...
And now, let's use it!
for (auto i: rangeView(set, 1, 10)) {
// iterate through the second to the ninth element
}
Upvotes: 9
Reputation: 63946
You can't in a set
. Use the traditional for
syntax or maintain your own index counter.
You can in a vector
or other container with a flat layout like std::array
or a C-style array. Change it to use a reference.:
for (auto &i: S)
Then you can compare the address of i
with the address of s[0]
to get the index.
Upvotes: 2
Reputation: 75150
For the general case, you'd have to use a seperate variable:
int i = 0;
for (auto x : s)
cout << (i++ ? " " : "") << x << endl;
There are, of course, tricks for certain containers like vector
, but none work for every container.
You would probably be better off using the plain for
loop for this purpose.
Upvotes: 2
Reputation: 133112
No, you can't.
for (... : ...)
is called for
instead of foreach
only for the reason of not introducing a new keyword. The whole point of foreach
is a quick short syntax for iterating all elements without caring for their index. For all other situations there's simple for
which serves its purpose quite effectively.
Upvotes: 2