#include <iostream>
#include <boost/range/iterator_range.hpp>
int main()
{
const int array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// Just process the first element separately. No checks required in the loop.
std::cout << *std::begin(array);
for (const auto& item : boost::make_iterator_range(array, 1, 0))
{
std::cout << ", " << item;
}
}
--
Не можешь достичь желаемого — пожелай достигнутого.
Здравствуйте, rg45, Вы писали:
M>>Для нового range-for'а есть какой-нибудь вариант?
R>При помощи boost::make_iterator_range можно вырезать подпоследовательности из последовательностей самых разных типов (в т.ч. и встроенных массивов):
Только встроенные средства
R>P.S. Сложноватым пример показался? Я упростил немного.
???
R>
R>#include <iostream>
R>#include <boost/range/iterator_range.hpp>
R>int main()
R>{
R> const int array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
R> // Just process the first element separately. No checks required in the loop.
R> std::cout << *std::begin(array);
R> for (const auto& item : boost::make_iterator_range(array, 1, 0))
R> {
R> std::cout << ", " << item;
R> }
R>}
R>
Как минимум, этот код не будет корректно работать для пустого контейнера.
M>>Как минимум, этот код не будет корректно работать для пустого контейнера.
R>Все верно. Потому что этот код максимально упрощен. Если хочется универсальности, смотри первоначальный ("сложный") вариант:
Я бы заменил, все-таки, "идеальный" на "подходящий для большинства типовых случаев". Во-первых потому, что этот вариант не универсален — он не подходит для случаев сгенерированных или трансформировнных последовательностей, где разымерование итераторов возвращает rvalue. Также он не подходит для lvalue-последовательностей, где один и тот же елемент может встретиться более одного раза. Использовать этот подход в качестве максимально общего не получится никак. А ты говоришь "идеальный".
А во-вторых, внесение внутрь цикла операции, которую реально нужно выпольнить только один раз, как бы это помягче назвать... Непрофессионализм, так скажем. И дело тут совсем не в быстродействии.
--
Не можешь достичь желаемого — пожелай достигнутого.
R>Я бы заменил, все-таки, "идеальный" на "подходящий для большинства типовых случаев".
Ну я же сказал "практически идеальный"
R>Во-первых потому, что этот вариант не универсален — о не подходит для случаев. сгенерированных или трансформировнных последовательностей, где разымерование итераторов возвращает rvalue.
Для стандартных контейнеров подходит — и хорошо.
R>Также он не подходит для lvalue-последовательностей, где один и тот же елемент может встретиться более одного раза.
Можно пример такого?
R>А во-вторых, выполнение в цикле операции, которую реально нужно выпольнить только один раз, как бы это помягче назвать... Непрофессионализм, так скажем.
Не согласен. Во-первых, этот код возможно будет оптимизирован компилятором. Во-вторых, если первое не сработает, то весьма вероятно, что предсказатель процессора его вычислит. В-третьих, если это критично, то его всегда можно переписать "правильно". В четвертых, я такую конструкцию обычно использую при выводе в поток — в лог, и тп. А ввод-вывод, а тем более плюсовые потоки — это тормоза еще те, и беспокоиться о таких мелочах — это как экономить на спичках
Но самое главное — это читабельность. В твоем варианте она хуже. Я бы сказал, что твой вариант — это случай преждевременной оптимизации.
R>>Также он не подходит для lvalue-последовательностей, где один и тот же елемент может встретиться более одного раза.
M>Можно пример такого?
Пожалуйста. В этом примере ты проходишь по последовательности из десяти элементов и получаещь, что каждый элемент является и первым, и последним одновременно.
Только не придирайся, пожалуйта, к использованияю boost::adaptors::indirected — он использован исключительно ради упрощения примера. Использование адаптеров контейнеров давно уже не является прерогативой буста и пишется такой адаттор за считанные минуты в несколько строк.
#include <iostream>
#include <vector>
#include <boost/range/adaptor/indirected.hpp>
int main()
{
std::cout << std::boolalpha;
int t = 42;
std::vector<const int*> v(10, &t);
const auto cont = v | boost::adaptors::indirected;
for (auto& a : cont)
{
auto first = &a == &cont.front();
auto last = &a == &cont.back();
std::cout << first << ", " << last << std::endl;
}
}
--
Не можешь достичь желаемого — пожелай достигнутого.
Здравствуйте, rg45, Вы писали:
R>>>Также он не подходит для lvalue-последовательностей, где один и тот же елемент может встретиться более одного раза.
M>>Можно пример такого?
R>Пожалуйста. В этом примере ты проходишь по последовательности из десяти элементов и получаещь, что каждый элемент является и первым, и последним одновременно.
Ок.
R>Только не придирайся, пожалуйта, к использованияю boost::adaptors::indirected — он использован исключительно ради упрощения примера.
Хорошо, не буду
Да, надо знать, что когда можно, а когда нельзя. Шаблонную функцию для произвольного контейнера я не стал бы так писать, а если по месту для какого-нибудь вектора надо по-быстренькому — то не вижу проблем
R>А во-вторых, выполнение в цикле операции, которую реально нужно выпольнить только один раз, как бы это помягче назвать... Непрофессионализм, так скажем. И дело тут совсем не в быстродействии.
M>Не согласен. Во-первых, этот код возможно будет оптимизирован компилятором. Во-вторых, если первое не сработает, то весьма вероятно, что предсказатель процессора его вычислит. В-третьих, если это критично, то его всегда можно переписать "правильно". В четвертых, я такую конструкцию обычно использую при выводе в поток — в лог, и тп. А ввод-вывод, а тем более плюсовые потоки — это тормоза еще те, и беспокоиться о таких мелочах — это как экономить на спичках
Однако. Вырезал слова "и дело тут совсем не в быстродействии" и начал отстаивать свою позицию именно с точки зрения быстродействия
M>Но самое главное — это читабельность. В твоем варианте она хуже.
Я не считаю, что внесение внутрь цикла кода, который заведомо должен выполниться только один раз, как-то улучшает читабельность. Все как раз наоборот.
M>Я бы сказал, что твой вариант — это случай преждевременной оптимизации.
Ну ты для начала предоставь РАВНОЦЕННЫЙ вариант, потом можно будет сравнить. А пока говорить-то не о чем.
--
Не можешь достичь желаемого — пожелай достигнутого.
Здравствуйте, Marty, Вы писали:
M>Да, надо знать, что когда можно, а когда нельзя. Шаблонную функцию для произвольного контейнера я не стал бы так писать, а если по месту для какого-нибудь вектора надо по-быстренькому — то не вижу проблем
Ну собственно об этом я и говорил — слово "идеальный" как-то не очень уместно в этом случае
--
Не можешь достичь желаемого — пожелай достигнутого.
Здравствуйте, rg45, Вы писали:
R>Однако. Вырезал слова "и дело тут совсем не в быстродействии" и начал отстаивать свою позицию именно с точки зрения быстродействия
Сорян, я не специально. Просто просмотрел
M>>Но самое главное — это читабельность. В твоем варианте она хуже.
R>Я не считаю, что внесение внутрь цикла кода, который заведомо должен выполниться только один раз, как-то улучшает читабельность. Все как раз наоборот.
#include <iostream>
#include <vector>
int main()
{
std::vector<int> vec(10, 5);
for( const auto &v : vec )
{
if (&v!=!vec.front()) std::cout<<", ";
std::cout<<v;
}
}
M>>Я бы сказал, что твой вариант — это случай преждевременной оптимизации.
R>Ну ты для начала предоставь РАВНОЦЕННЫЙ вариант, потом можно будет сравнить. А пока говорить-то не о чем.
Не кипятись
Ну, и для начала — почему именно равноценный? Я же сказал, что в простых известных случаях предложенный Went'ом вариант проще и удобней в использовании.
Здравствуйте, Marty, Вы писали: M>>>Я бы сказал, что твой вариант — это случай преждевременной оптимизации. R>>Ну ты для начала предоставь РАВНОЦЕННЫЙ вариант, потом можно будет сравнить. А пока говорить-то не о чем. M>Ну, и для начала — почему именно равноценный? Я же сказал, что в простых известных случаях предложенный Went'ом вариант проще и удобней в использовании.
Ну потому, что когда ты это сделаешь, ты поймешь, что мой код так написан именно из соображений лучшей структуры кода и читабельности, а вовсе не ради оптимизации. Те же варианты, которые ты до сих пор предлагал, не релевантны для такого сравнения. M>ЗЫ Кстати, а зачем буст?
Затем, что в той версии gcc, что в ideone, этих функций просто еще нету. Требование "чтоб без буста" ты ведь позже выдвинул. M>Чем плох такой вариант:
Да ни чем не хуже. Только зачем ты этот топик создавал, если вариант обычного for тебя тоже устраивает, оказывается
Здравствуйте, rg45, Вы писали:
M>>Да, надо знать, что когда можно, а когда нельзя. Шаблонную функцию для произвольного контейнера я не стал бы так писать, а если по месту для какого-нибудь вектора надо по-быстренькому — то не вижу проблем
R>Ну собственно об этом я и говорил — слово "идеальный" как-то не очень уместно в этом случае
При этом сам вырезаешь из: "практически идеальный"