Но даже если мы ни для чего не используем e, эта формулировка удобна, сделать ошибку сложнее.Другой способ (для проверки изменения значений) более утомителен (так как нам нужно обрабатывать последний диапазон специально [...])
Зависит от того, как вы интерпретируете 'обработку последнего диапазонаособенно ':
auto begin = v.begin();
// we might need some initialization for whatever on *begin...
for(Iterator i = begin + 1; ; ++i)
{
if(i == v.end() || *i != *begin)
{
// handle range single element of range [begin, ???);
if(i == v.end())
break;
begin = i;
// re-initialize next range
}
}
Никакой специальной обработки для последнего диапазона - только, возможно, потребуется код инициализации дважды ...
Подход с вложенным циклом:
auto begin = v.begin();
for(;;)
{
// initialize first/next range using *begin
for(Iterator i = begin + 1; ; ++i)
{
if(i == v.end() || *i != *begin)
{
// handle range single element of range [begin, ???);
if(i == v.end())
goto LOOP_EXIT;
begin = i;
break;
}
}
}
LOOP_EXIT:
// go on
// if nothing left to do in function, we might prefer returning over going to...
Более элегантно?Признаюсь, я сам сомневаюсь ... Оба подхода избегают повторения в одном и том же диапазоне дважды (сначала для нахождения конца, затем для фактической итерации).И если мы создадим нашу собственную библиотечную функцию из:
template <typename Iterator, typename RangeInitializer, typename ElementHandler>
void iterateOverEqualRanges
(
Iterator begin, Iterator end,
RangeInitializer ri, ElementHandler eh
)
{
// the one of the two approaches you like better
// or your own variation of...
}
, мы могли бы затем использовать ее следующим образом:
std::vector<...> v;
iterateOverEqualRanges
(
v.begin(), v.end(),
[] (auto begin) { /* ... */ },
[] (auto current) { /* ... */ }
);
Теперь, наконец, это похоже на, например, std::for_each
, неэто?