range based for - первый/последний?
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 13.03.19 00:38
Оценка: +1
Здравствуйте!

Для цикла типа:

for( autp a : cont)
{
    doWith(a);
}


можно определить первый/последний элемент?


Раньше делал типа того:

for( bla::bla<bla>::const_iterator bit = cont.begin(); bit != cont.end(); ++bit)
{
    if (bit == cont.begin())
        std::cout<<", ";
}


для вывода разных списков и тп.

Для нового range-for'а есть какой-нибудь вариант?
Маньяк Робокряк колесит по городу
Re: range based for - первый/последний?
От: rg45 СССР  
Дата: 13.03.19 07:08
Оценка:
Здравствуйте, Marty, Вы писали:

M>Для нового range-for'а есть какой-нибудь вариант?


При помощи boost::make_iterator_range можно вырезать подпоследовательности из последовательностей самых разных типов (в т.ч. и встроенных массивов):

P.S. Сложноватым пример показался? Я упростил немного.

https://ideone.com/CSSJR2

#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;
    }
}
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 13.03.2019 13:20 rg45 . Предыдущая версия . Еще …
Отредактировано 13.03.2019 10:02 rg45 . Предыдущая версия .
Отредактировано 13.03.2019 10:02 rg45 . Предыдущая версия .
Re: range based for - первый/последний?
От: Went  
Дата: 13.03.19 08:53
Оценка: +4
Здравствуйте, Marty, Вы писали:

M>Здравствуйте!

M>Для цикла типа:
M>
M>for( autp a : cont)
M>{
M>    doWith(a);
M>}
M>

M>можно определить первый/последний элемент?
В частном случае я бы сделал так:
for (auto& a : cont)
{
  auto first = &a == &cont.front();
  auto last = &a == &cont.back();
}

Но, понятное дело, это в частном случае.
Re: range based for - первый/последний?
От: B0FEE664  
Дата: 13.03.19 16:27
Оценка: 2 (1)
Здравствуйте, Marty, Вы писали:

M>Для нового range-for'а есть какой-нибудь вариант?


Вариант в простом случае:
const char* comma = "";
for( auto a : cont)
{
  std::cout<< comma << a;
  comma = ", ";
}
И каждый день — без права на ошибку...
Re[2]: range based for - первый/последний?
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 13.03.19 16:44
Оценка:
Здравствуйте, B0FEE664, Вы писали:


M>>Для нового range-for'а есть какой-нибудь вариант?


BFE>Вариант в простом случае:

BFE>
BFE>const char* comma = "";
BFE>for( auto a : cont)
BFE>{
BFE>  std::cout<< comma << a;
BFE>  comma = ", ";
BFE>}
BFE>


Спс. Но вариант с булевым флагом имхо лучше
Маньяк Робокряк колесит по городу
Re[2]: range based for - первый/последний?
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 13.03.19 16:44
Оценка:
Здравствуйте, Went, Вы писали:

M>>можно определить первый/последний элемент?

W>В частном случае я бы сделал так:
W>
W>for (auto& a : cont)
W>{
W>  auto first = &a == &cont.front();
W>  auto last = &a == &cont.back();
W>}
W>

W>Но, понятное дело, это в частном случае.


В принципе, вариант не плох
Маньяк Робокряк колесит по городу
Re[2]: range based for - первый/последний?
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 13.03.19 16:47
Оценка:
Здравствуйте, 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>


Как минимум, этот код не будет корректно работать для пустого контейнера.
Маньяк Робокряк колесит по городу
Re[3]: range based for - первый/последний?
От: rg45 СССР  
Дата: 13.03.19 17:38
Оценка:
Здравствуйте, Marty, Вы писали:


M>Как минимум, этот код не будет корректно работать для пустого контейнера.


Все верно. Потому что этот код максимально упрощен. Если хочется универсальности, смотри первоначальный ("сложный") вариант:

https://ideone.com/OSuZuC

#include <iostream>
#include <boost/range/iterator_range.hpp>

template <typename SequenceT>
void print_sequence(const SequenceT& seq)
{
    if (!std::empty(seq))
    {
        std::cout << "[" << std::front(seq);
        
        for (const auto& item : boost::make_iterator_range(seq, 1, 0))
        {
            std::cout << ", " << item;
        }
        std::cout << "]"<< std::endl;
    }
}

int main()
{
    const int array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    print_sequence(array);
}
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 14.03.2019 8:18 rg45 . Предыдущая версия . Еще …
Отредактировано 13.03.2019 17:38 rg45 . Предыдущая версия .
Re[4]: range based for - первый/последний?
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 13.03.19 17:43
Оценка:
Здравствуйте, rg45, Вы писали:


M>>Как минимум, этот код не будет корректно работать для пустого контейнера.


R>Все верно. Потому что этот код максимально упрощен. Если хочется универсальности, смотри первоначальный ("сложный") вариант:


Я вот только не видел первоначального варианта

R>https://ideone.com/OSuZuC


Сложно. И буст, а не стандартный C++

Вариант от коллеги Went'а практически идеален
Автор: Went
Дата: 13.03.19
Маньяк Робокряк колесит по городу
Re[5]: range based for - первый/последний?
От: rg45 СССР  
Дата: 13.03.19 17:54
Оценка: +1
Здравствуйте, Marty, Вы писали:

M>Вариант от коллеги Went'а практически идеален
Автор: Went
Дата: 13.03.19


Я бы заменил, все-таки, "идеальный" на "подходящий для большинства типовых случаев". Во-первых потому, что этот вариант не универсален — он не подходит для случаев сгенерированных или трансформировнных последовательностей, где разымерование итераторов возвращает rvalue. Также он не подходит для lvalue-последовательностей, где один и тот же елемент может встретиться более одного раза. Использовать этот подход в качестве максимально общего не получится никак. А ты говоришь "идеальный".

А во-вторых, внесение внутрь цикла операции, которую реально нужно выпольнить только один раз, как бы это помягче назвать... Непрофессионализм, так скажем. И дело тут совсем не в быстродействии.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 13.03.2019 18:06 rg45 . Предыдущая версия . Еще …
Отредактировано 13.03.2019 18:03 rg45 . Предыдущая версия .
Отредактировано 13.03.2019 18:02 rg45 . Предыдущая версия .
Отредактировано 13.03.2019 18:00 rg45 . Предыдущая версия .
Отредактировано 13.03.2019 17:55 rg45 . Предыдущая версия .
Re: range based for - первый/последний?
От: andrey.desman  
Дата: 13.03.19 18:09
Оценка: +5
Здравствуйте, Marty, Вы писали:

M>для вывода разных списков и тп.

M>Для нового range-for'а есть какой-нибудь вариант?

Есть. Не использовать новый range-for там, где он тебе не подходит.
Сам создаешь себе проблемы, а потом героически их преодолеваешь. Зато for модный.
Re[6]: range based for - первый/последний?
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 13.03.19 18:09
Оценка:
Здравствуйте, rg45, Вы писали:

M>>Вариант от коллеги Went'а практически идеален
Автор: Went
Дата: 13.03.19


R>Я бы заменил, все-таки, "идеальный" на "подходящий для большинства типовых случаев".


Ну я же сказал "практически идеальный"

R>Во-первых потому, что этот вариант не универсален — о не подходит для случаев. сгенерированных или трансформировнных последовательностей, где разымерование итераторов возвращает rvalue.


Для стандартных контейнеров подходит — и хорошо.


R>Также он не подходит для lvalue-последовательностей, где один и тот же елемент может встретиться более одного раза.


Можно пример такого?


R>А во-вторых, выполнение в цикле операции, которую реально нужно выпольнить только один раз, как бы это помягче назвать... Непрофессионализм, так скажем.


Не согласен. Во-первых, этот код возможно будет оптимизирован компилятором. Во-вторых, если первое не сработает, то весьма вероятно, что предсказатель процессора его вычислит. В-третьих, если это критично, то его всегда можно переписать "правильно". В четвертых, я такую конструкцию обычно использую при выводе в поток — в лог, и тп. А ввод-вывод, а тем более плюсовые потоки — это тормоза еще те, и беспокоиться о таких мелочах — это как экономить на спичках

Но самое главное — это читабельность. В твоем варианте она хуже. Я бы сказал, что твой вариант — это случай преждевременной оптимизации.
Маньяк Робокряк колесит по городу
Re[2]: range based for - первый/последний?
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 13.03.19 18:12
Оценка:
Здравствуйте, andrey.desman, Вы писали:

AD>Есть. Не использовать новый range-for там, где он тебе не подходит.


Ну, он хорош своей лаконичностью, и грех его не использовать почаще.


AD>Сам создаешь себе проблемы, а потом героически их преодолеваешь.


Это C++, с ним всегда так


AD>Зато for модный.


Дык
Маньяк Робокряк колесит по городу
Re[7]: range based for - первый/последний?
От: rg45 СССР  
Дата: 13.03.19 18:27
Оценка:
Здравствуйте, Marty, Вы писали:


R>>Также он не подходит для lvalue-последовательностей, где один и тот же елемент может встретиться более одного раза.


M>Можно пример такого?


Пожалуйста. В этом примере ты проходишь по последовательности из десяти элементов и получаещь, что каждый элемент является и первым, и последним одновременно.

Только не придирайся, пожалуйта, к использованияю boost::adaptors::indirected — он использован исключительно ради упрощения примера. Использование адаптеров контейнеров давно уже не является прерогативой буста и пишется такой адаттор за считанные минуты в несколько строк.

https://ideone.com/YqTMaO

#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;
   }

}
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 13.03.2019 18:30 rg45 . Предыдущая версия .
Re[8]: range based for - первый/последний?
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 13.03.19 18:41
Оценка:
Здравствуйте, rg45, Вы писали:

R>>>Также он не подходит для lvalue-последовательностей, где один и тот же елемент может встретиться более одного раза.


M>>Можно пример такого?


R>Пожалуйста. В этом примере ты проходишь по последовательности из десяти элементов и получаещь, что каждый элемент является и первым, и последним одновременно.


Ок.


R>Только не придирайся, пожалуйта, к использованияю boost::adaptors::indirected — он использован исключительно ради упрощения примера.


Хорошо, не буду


Да, надо знать, что когда можно, а когда нельзя. Шаблонную функцию для произвольного контейнера я не стал бы так писать, а если по месту для какого-нибудь вектора надо по-быстренькому — то не вижу проблем
Маньяк Робокряк колесит по городу
Re[7]: range based for - первый/последний?
От: rg45 СССР  
Дата: 13.03.19 18:45
Оценка:
Здравствуйте, Marty, Вы писали:


R>А во-вторых, выполнение в цикле операции, которую реально нужно выпольнить только один раз, как бы это помягче назвать... Непрофессионализм, так скажем. И дело тут совсем не в быстродействии.


M>Не согласен. Во-первых, этот код возможно будет оптимизирован компилятором. Во-вторых, если первое не сработает, то весьма вероятно, что предсказатель процессора его вычислит. В-третьих, если это критично, то его всегда можно переписать "правильно". В четвертых, я такую конструкцию обычно использую при выводе в поток — в лог, и тп. А ввод-вывод, а тем более плюсовые потоки — это тормоза еще те, и беспокоиться о таких мелочах — это как экономить на спичках


Однако. Вырезал слова "и дело тут совсем не в быстродействии" и начал отстаивать свою позицию именно с точки зрения быстродействия

M>Но самое главное — это читабельность. В твоем варианте она хуже.


Я не считаю, что внесение внутрь цикла кода, который заведомо должен выполниться только один раз, как-то улучшает читабельность. Все как раз наоборот.

M>Я бы сказал, что твой вариант — это случай преждевременной оптимизации.


Ну ты для начала предоставь РАВНОЦЕННЫЙ вариант, потом можно будет сравнить. А пока говорить-то не о чем.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 13.03.2019 18:45 rg45 . Предыдущая версия .
Re[9]: range based for - первый/последний?
От: rg45 СССР  
Дата: 13.03.19 18:47
Оценка:
Здравствуйте, Marty, Вы писали:

M>Да, надо знать, что когда можно, а когда нельзя. Шаблонную функцию для произвольного контейнера я не стал бы так писать, а если по месту для какого-нибудь вектора надо по-быстренькому — то не вижу проблем


Ну собственно об этом я и говорил — слово "идеальный" как-то не очень уместно в этом случае
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[8]: range based for - первый/последний?
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 13.03.19 19:03
Оценка:
Здравствуйте, rg45, Вы писали:

R>Однако. Вырезал слова "и дело тут совсем не в быстродействии" и начал отстаивать свою позицию именно с точки зрения быстродействия


Сорян, я не специально. Просто просмотрел


M>>Но самое главное — это читабельность. В твоем варианте она хуже.


R>Я не считаю, что внесение внутрь цикла кода, который заведомо должен выполниться только один раз, как-то улучшает читабельность. Все как раз наоборот.


Давай сравним:

#include <iostream>
#include <boost/range/iterator_range.hpp>

template <typename SequenceT>
void print_sequence(const SequenceT& seq)
{
    if (!boost::empty(seq))
    {
        std::cout << "[" << *std::begin(seq);
        
        for (const auto& item : boost::make_iterator_range(seq, 1, 0))
        {
            std::cout << ", " << item;
        }
        std::cout << "]"<< std::endl;
    }
}

int main()
{
    const int array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    print_sequence(array);
}


#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'ом вариант проще и удобней в использовании.


ЗЫ Кстати, а зачем буст? Чем плох такой вариант:

#include <iostream>
#include <boost/range/iterator_range.hpp>

template <typename SequenceT>
void print_sequence(const SequenceT& seq)
{
    if (!boost::empty(seq))
    {
        auto it = std::begin(seq);
        std::cout << "[" << *it;
        ++it;
        
        for (; it!=std::end(seq); ++it)
        {
            std::cout << ", " << *it;
        }
        std::cout << "]"<< std::endl;
    }
}

int main()
{
    const int array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    print_sequence(array);
}
Маньяк Робокряк колесит по городу
Re[9]: range based for - первый/последний?
От: rg45 СССР  
Дата: 13.03.19 19:20
Оценка:
Здравствуйте, Marty, Вы писали:

M>>>Я бы сказал, что твой вариант — это случай преждевременной оптимизации.


R>>Ну ты для начала предоставь РАВНОЦЕННЫЙ вариант, потом можно будет сравнить. А пока говорить-то не о чем.


M>Ну, и для начала — почему именно равноценный? Я же сказал, что в простых известных случаях предложенный Went'ом вариант проще и удобней в использовании.


Ну потому, что когда ты это сделаешь, ты поймешь, что мой код так написан именно из соображений лучшей структуры кода и читабельности, а вовсе не ради оптимизации. Те же варианты, которые ты до сих пор предлагал, не релевантны для такого сравнения.

M>ЗЫ Кстати, а зачем буст?


Затем, что в той версии gcc, что в ideone, этих функций просто еще нету. Требование "чтоб без буста" ты ведь позже выдвинул.

M>Чем плох такой вариант:


Да ни чем не хуже. Только зачем ты этот топик создавал, если вариант обычного for тебя тоже устраивает, оказывается

  ccode
M>
M>#include <iostream>
M>#include <boost/range/iterator_range.hpp>

M>template <typename SequenceT>
M>void print_sequence(const SequenceT& seq)
M>{
M>    if (!boost::empty(seq))
M>    {
M>        auto it = std::begin(seq);
M>        std::cout << "[" << *it;
M>        ++it;
        
M>        for (; it!=std::end(seq); ++it)
M>        {
M>            std::cout << ", " << *it;
M>        }
M>        std::cout << "]"<< std::endl;
M>    }
M>}

M>int main()
M>{
M>    const int array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

M>    print_sequence(array);
M>}
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 13.03.2019 19:22 rg45 . Предыдущая версия .
Re[10]: range based for - первый/последний?
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 13.03.19 19:21
Оценка:
Здравствуйте, rg45, Вы писали:

M>>Да, надо знать, что когда можно, а когда нельзя. Шаблонную функцию для произвольного контейнера я не стал бы так писать, а если по месту для какого-нибудь вектора надо по-быстренькому — то не вижу проблем


R>Ну собственно об этом я и говорил — слово "идеальный" как-то не очень уместно в этом случае


При этом сам вырезаешь из: "практически идеальный"

Лан, проехали
Маньяк Робокряк колесит по городу
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.