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>Ну собственно об этом я и говорил — слово "идеальный" как-то не очень уместно в этом случае


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

Лан, проехали
Маньяк Робокряк колесит по городу
Re[10]: range based for - первый/последний?
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 13.03.19 19:29
Оценка:
Здравствуйте, rg45, Вы писали:

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


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


Ну, вообще я интересовался языковыми средствами C++ из новых стандартов, и думал, что, возможно, предусмотрено какое-то языковое средство для определения крайних случаев.


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


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


Да если столько писанины в итоге, то уже как-то и не важно, в каком виде этот несчастный for будет
Маньяк Робокряк колесит по городу
Re[11]: range based for - первый/последний?
От: rg45 СССР  
Дата: 13.03.19 19:39
Оценка: +1
Здравствуйте, Marty, Вы писали:


M>Да если столько писанины в итоге, то уже как-то и не важно, в каком виде этот несчастный for будет


Ну смотри, я тут походу пьессы уже предоставил два варианта — один максимально универсальный
Автор: rg45
Дата: 13.03.19
, и его сложность как раз и обусловлена утиверсальностью. Второй вариант
Автор: rg45
Дата: 13.03.19
заточен под конткретное место использования. И я бы не сказал, что выглядит он слишком уж сложно:

    std::cout << *std::begin(array);
        
    for (const auto& item : boost::make_iterator_range(array, 1, 0))
    {
        std::cout << ", " << item;
    }


Неужели это сложнее или читается хуже чем:

   for (auto& a : cont)
   {
      auto first = &a == &cont.front();
  
      if (!first)
      {
          std::cout << ", ";
      }

      std::cout << item;
   }


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


M>>Да если столько писанины в итоге, то уже как-то и не важно, в каком виде этот несчастный for будет


R>Ну смотри, я тут походу пьессы уже предоставил два варианта — один максимально универсальный
Автор: rg45
Дата: 13.03.19
, и его сложность как раз и обусловлена утиверсальностью. Второй вариант
Автор: rg45
Дата: 13.03.19
заточен под конткретное место использования. И я бы не сказал, что выглядит он слишком уж сложно:


Но он тянет буст.


R>Неужели это сложнее или читается хуже чем:


Ну, после того как ты его максимально удлиннил, то конечно этот вариант стал похуже


R>Ты не согласен?


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


R>>Неужели это сложнее или читается хуже чем:


M>Ну, после того как ты его максимально удлиннил, то конечно этот вариант стал похуже



Да не вопрос, давай упростим, но только оба варианта!

    std::cout << cont.front();

    for (auto& a : boost::make_iterator_range(cont, 1, 0))
        std::cout << ", " << a;


   for (auto& a : cont)
   {
      if (&a != &cont.front())
          std::cout << ", ";

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


M>>Ну, после того как ты его максимально удлиннил, то конечно этот вариант стал похуже


R>Да не вопрос, давай упростим, но только оба варианта!


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


R>>Да не вопрос, давай упростим, но только оба варианта!


M>Нормас!


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

R>>>Да не вопрос, давай упростим, но только оба варианта!


M>>Нормас!


R>Не, ты скажи, что я тебя убедил


Неа

1) Таки буст.
2) Таки то, что с пустым вектором не работает. Это таки критичнее, чем то, что мой вариант не работает с произвольным контейнеромадаптером
Маньяк Робокряк колесит по городу
Re[17]: range based for - первый/последний?
От: rg45 СССР  
Дата: 13.03.19 20:29
Оценка:
Здравствуйте, Marty, Вы писали:

M>2) Таки то, что с пустым вектором не работает. Это таки критичнее, чем то, что мой вариант не работает с произвольным контейнеромадаптером


Ай, блин, я ждал, что ты это скажешь!

Лады, замечание справедливое, подчиняюсь.

    if (!cont.empty())
    {
        std::cout << cont.front();

        for (auto& a : boost::make_iterator_range(cont, 1, 0))
            std::cout << ", " << a;
    }


   for (auto& a : cont)
   {
      if (&a != &cont.front())
          std::cout << ", ";

      std::cout << item;
   }


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

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

M>>2) Таки то, что с пустым вектором не работает. Это таки критичнее, чем то, что мой вариант не работает с произвольным контейнеромадаптером


R>Ай, блин, я ждал, что ты это скажешь!


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


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


Согласен.


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


Имхо — вкусовщина и дело привычки


R>Ну вот только буст остается. Но я лично против буста ничего не имею.


По возможности избегаю. Сейчас вообще продакшн код пишу для STMки, а там у кейла такая ситуёвина, что компилятор вроде допилили до 11го стандарта, а библиотеки — забыли, поленились, или бабла на это зажали. Это вроде даже не кейловская проблема, а армовская. Буст втуда вкорячивать не вижу особого смысла

С другой стороны, иногда пишу всякие утилитки для локального вспоможения на MSVC, C++17, а код, по возможности, для одних и тех же случаев стараюсь переиспользовать и там и там. Более новые стандарты пробую использовать только там, что в STMку точно не пролезет. А с нынешним достаточно резвым темпом принятия фич в стандарт буст таскать ради пары мелочей смысла не вижу
Маньяк Робокряк колесит по городу
Re: range based for - первый/последний?
От: B0FEE664  
Дата: 13.03.19 22:54
Оценка:
Здравствуйте, Marty, Вы писали:

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

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

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

Можно, но сложно. Есть три варианта:
1) написать прокси для cont;
2) написать прокси для a;
3) написать прокси для тела цикла.

На мой взгляд последний вариант самый перспективный, но он же и самый труднопонимаемый/читаемый:
  std::function<void(int)> f = [&] (int n) { 
                                             f = [](int n){ std::cout << ", " << n; };
                                             std::cout << n;
                                           };
  for(auto item : v)
    f(item);


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

Есть вот такой модный вариант, но он не то, что вы просите:
  if ( auto it = std::begin(v), itEnd = std::end(v); itEnd != it )
  {
    std::cout << *it;
    for(++it; itEnd != it; ++it)
    {
      std::cout << ", " << *it;
    }
  }
И каждый день — без права на ошибку...
Re: range based for - первый/последний?
От: PM  
Дата: 14.03.19 06:52
Оценка: 9 (2)
Здравствуйте, Marty, Вы писали:


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


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


Если только для вывода, то есть https://en.cppreference.com/w/cpp/experimental/ostream_joiner

#include <algorithm>
#include <experimental/iterator>
#include <iostream>
#include <iterator>
 
int main()
{
    int i[] = {1, 2, 3, 4, 5};
    std::copy(std::begin(i),
              std::end(i),
              std::experimental::make_ostream_joiner(std::cout, ", "));
}


Output:

1, 2, 3, 4, 5

Re[2]: range based for - первый/последний?
От: rg45 СССР  
Дата: 14.03.19 07:56
Оценка:
Здравствуйте, B0FEE664, Вы писали:

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

BFE>Есть вот такой модный вариант, но он не то, что вы просите:
BFE>
BFE>  if ( auto it = std::begin(v), itEnd = std::end(v); itEnd != it )
BFE>  {
BFE>    std::cout << *it;
BFE>    for(++it; itEnd != it; ++it)
BFE>    {
BFE>      std::cout << ", " << *it;
BFE>    }
BFE>  }
BFE>


Вот эта многоэтажность в условии глаз не радует совершенно. Зачем вообще здесь что-то выдумывать, когда все предельно просто:

  if (!std::empty(v))
  {
    std::cout << std::front(v);
    for(auto it = std::begin(v) + 1; it != std::end(v); ++it)
    {
      std::cout << ", " << *it;
    }
  }


Ну правда std::empty и std::front появляются только в С++17. Но их отсутствие легко восполняется, могу показать, если нужно.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 14.03.2019 9:13 rg45 . Предыдущая версия . Еще …
Отредактировано 14.03.2019 8:13 rg45 . Предыдущая версия .
Отредактировано 14.03.2019 8:09 rg45 . Предыдущая версия .
Отредактировано 14.03.2019 7:57 rg45 . Предыдущая версия .
Re[3]: range based for - первый/последний?
От: B0FEE664  
Дата: 14.03.19 13:17
Оценка:
Здравствуйте, rg45, Вы писали:

R>Вот эта многоэтажность в условии глаз не радует совершенно.

Я пробовал так:
if ( auto [it, itEnd] = {std::begin(v), std::end(v)}; itEnd != it )

но не собралось.

R>Зачем вообще здесь что-то выдумывать, когда все предельно просто:

Затем, чтобы избежать вызова std::end(v) на каждую проверку условия цикла.
И каждый день — без права на ошибку...
Re[4]: range based for - первый/последний?
От: _NN_ www.nemerleweb.com
Дата: 14.03.19 13:30
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Здравствуйте, rg45, Вы писали:


R>>Вот эта многоэтажность в условии глаз не радует совершенно.

BFE>Я пробовал так:
BFE>
BFE>if ( auto [it, itEnd] = {std::begin(v), std::end(v)}; itEnd != it )
BFE>

BFE>но не собралось.

Начиная с C++17 типы std::begin и std::end не обязаны совпадать.
Собственно for-range разворачивается в такой код.
https://en.cppreference.com/w/cpp/language/range-for

До C++17
{

    auto && __range = range_expression ;
    for (auto __begin = begin_expr, __end = end_expr; __begin != __end; ++__begin) {

        range_declaration = *__begin;
        loop_statement

    }

}


C++17
{

    auto && __range = range_expression ;
    auto __begin = begin_expr ;
    auto __end = end_expr ;
    for ( ; __begin != __end; ++__begin) {

        range_declaration = *__begin;
        loop_statement

    }

}



R>>Зачем вообще здесь что-то выдумывать, когда все предельно просто:

BFE>Затем, чтобы избежать вызова std::end(v) на каждую проверку условия цикла.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[3]: range based for - первый/последний?
От: flаt  
Дата: 14.03.19 13:33
Оценка:
Здравствуйте, Marty, Вы писали:

M>Спс. Но вариант с булевым флагом имхо лучше


Прост, лаконичен, изящен. И нет лишних проверок внутри цикла.
Re[5]: range based for - первый/последний?
От: B0FEE664  
Дата: 14.03.19 13:46
Оценка:
Здравствуйте, _NN_, Вы писали:

BFE>>Я пробовал так:

BFE>>
BFE>>if ( auto [it, itEnd] = {std::begin(v), std::end(v)}; itEnd != it )
BFE>>

BFE>>но не собралось.
_NN>Начиная с C++17 типы std::begin и std::end не обязаны совпадать.

Дело не в этом.
Вот такая конструкция не работает:
  int i1 = 1;
  int i2 = 2;
  auto [a, b] = {i1, i2};

А жаль.

проверял тут
И каждый день — без права на ошибку...
Re[4]: range based for - первый/последний?
От: rg45 СССР  
Дата: 14.03.19 13:58
Оценка:
Здравствуйте, B0FEE664, Вы писали:

R>>Зачем вообще здесь что-то выдумывать, когда все предельно просто:

BFE>Затем, чтобы избежать вызова std::end(v) на каждую проверку условия цикла.

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

Не будет там никакого ВЫЗОВА — в подавляющем-подавляющем большинстве случаев. А тех редких случаях, когда будет вызов — не факт, что именно он окажется узким горлышком. Ну и наконец, если при каком-то невероятнейшем раскладе это случится, то оптимизация будет тривиальной. Я только не понимаю, зачем нам сейчас рассматривать эту экзотику, хогда разговор на уровне "что такое хорошо и что такое плохо".
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 14.03.2019 14:08 rg45 . Предыдущая версия . Еще …
Отредактировано 14.03.2019 14:06 rg45 . Предыдущая версия .
Отредактировано 14.03.2019 14:05 rg45 . Предыдущая версия .
Re[6]: range based for - первый/последний?
От: andrey.desman  
Дата: 14.03.19 14:04
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Дело не в этом.

BFE>Вот такая конструкция не работает:
BFE>
BFE>  int i1 = 1;
BFE>  int i2 = 2;
BFE>  auto [a, b] = std::tuple{i1, i2};
BFE>

BFE>А жаль.

Ибо потому что через тупл надо, потому что тут присваивание, а значит {} описывает initializer_list вместо конструктора. Были бы разные типу у it и i2, то даже до этого не дошел бы.
Re[5]: range based for - первый/последний?
От: B0FEE664  
Дата: 14.03.19 14:14
Оценка:
Здравствуйте, rg45, Вы писали:

BFE>>Затем, чтобы избежать вызова std::end(v) на каждую проверку условия цикла.

R>Меня тут давеча в преждевременной оптимизации упрекали.
Это был не я.

R>Так вот это оно самое.

Да неужели? А писать ++it вместо it++ — тоже преждевременная оптимизация?
И каждый день — без права на ошибку...
Re: range based for - первый/последний?
От: Skorodum Россия  
Дата: 14.03.19 14:21
Оценка:
Здравствуйте, Marty, Вы писали:

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

С помощью std::reverse_iterator и небольшой шаблонной магии:
#include <iterator>
#include <string>
#include <iostream>
 
template <typename T>
struct reversion_wrapper { T& iterable; };
 
template <typename T>
auto begin (reversion_wrapper<T> w) { return std::rbegin(w.iterable); }
 
template <typename T>
auto end (reversion_wrapper<T> w) { return std::rend(w.iterable); }
 
template <typename T>
reversion_wrapper<T> reverse (T&& iterable) { return { iterable }; }
 
int main (int, char**)
{
    std::string foo("Hello World!");
    for (const auto& it: reverse(foo))
        std::cout << it;

    // Для выводна в обратном порядке, наверное, проще будет std::reverse_copy
    std::reverse_copy(foo.begin(), foo.end(), std::ostream_iterator<int>(std::cout));
    return 0;
}
reverse_iterator reverse_copy
Re[6]: range based for - первый/последний?
От: rg45 СССР  
Дата: 14.03.19 14:29
Оценка:
Здравствуйте, B0FEE664, Вы писали:

R>>Так вот это оно самое.

BFE>Да неужели?

Да точно-точно.

BFE>А писать ++it вместо it++ — тоже преждевременная оптимизация?


Нет. Но писать it++ вместо ++it — это преждевременная пессимизация. Зачем писать более сложное выражение, когда можно написать более простое при прочих равных условиях? Подробнее здесь: https://doc.lagout.org/programmation/C/CPP101.pdf, рекомендация №9: "Don't pessimize prematurely".
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 14.03.2019 14:31 rg45 . Предыдущая версия . Еще …
Отредактировано 14.03.2019 14:30 rg45 . Предыдущая версия .
Re[7]: range based for - первый/последний?
От: B0FEE664  
Дата: 14.03.19 14:42
Оценка:
Здравствуйте, andrey.desman, Вы писали:

AD>Ибо потому что через тупл надо, потому что тут присваивание, а значит {} описывает initializer_list вместо конструктора. Были бы разные типу у it и i2, то даже до этого не дошел бы.

А откуда тут initializer_list ? Зачем он тут?
struct A
{
    int n;
    char* s;
};
A a = {1, nullptr};



А если убрать присваивание, то почему не работает?
auto [a, b]{i1, i2};
И каждый день — без права на ошибку...
Re[8]: range based for - первый/последний?
От: andrey.desman  
Дата: 14.03.19 15:53
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Здравствуйте, andrey.desman, Вы писали:


AD>>Ибо потому что через тупл надо, потому что тут присваивание, а значит {} описывает initializer_list вместо конструктора. Были бы разные типу у it и i2, то даже до этого не дошел бы.

BFE>А откуда тут initializer_list ? Зачем он тут?

Потому что так придумали.
A std::initializer_list object is automatically constructed when: a braced-init-list is bound to auto, including in a ranged for loop

BFE>
BFE>struct A
BFE>{
BFE>    int n;
BFE>    char* s;
BFE>};
BFE>A a = {1, nullptr};
BFE>

BFE>

Это copy-list-initialization и там не initializer_list, а braced-init-list.

BFE>А если убрать присваивание, то почему не работает?

BFE>
BFE>auto [a, b]{i1, i2};
BFE>


С чего бы ей работать?
Смотри как объявляется structured binding https://en.cppreference.com/w/cpp/language/structured_binding.
В expression вообще запятой быть не положено, а когда ты = убираешь, то оно спотыкается уже на этом.

Твой изначальный код — это примерно следующее:
int i;
char c;

auto list = { i, c }; // initalizer_list, fail

auto [a, b] = list; // fail даже если list состояится как initializer_list, потому что он не массив и не тупл, значит привязка пойдет по членам класса.
Re[9]: range based for - первый/последний?
От: B0FEE664  
Дата: 14.03.19 16:44
Оценка:
Здравствуйте, andrey.desman, Вы писали:

BFE>>А откуда тут initializer_list ? Зачем он тут?

AD>Потому что так придумали.
Предположим, что так, хотя я сомневаюсь.

AD>A std::initializer_list object is automatically constructed when: a braced-init-list is bound to auto, including in a ranged for loop

А это наш случай? У нас structured binding, а не bound to auto. Разве это одно и тоже?

AD>Это copy-list-initialization и там не initializer_list, а braced-init-list.

Что говорит нам о том, что типы не обязаны быть одинаковыми. initializer_list не нужен.

BFE>>А если убрать присваивание, то почему не работает?

BFE>>
BFE>>auto [a, b]{i1, i2};
BFE>>

AD>С чего бы ей работать?
С того, что ничему не противоречит.
AD>Смотри как объявляется structured binding https://en.cppreference.com/w/cpp/language/structured_binding.
Я смотрел.

AD>В expression вообще запятой быть не положено, а когда ты = убираешь, то оно спотыкается уже на этом.

Не должно быть оператора запятая. Где у меня операторы?

AD>Твой изначальный код — это примерно следующее:

AD>auto list = { i, c }; // initalizer_list, fail
initalizer_list отсутствует в structured binding описании.

Предположим, что всё так, как вы пишите. Тогда получается, что это практически безполезная фича языка. Жаль, могла получиться красивая конструкция.
И каждый день — без права на ошибку...
Re[10]: range based for - первый/последний?
От: _NN_ www.nemerleweb.com
Дата: 14.03.19 17:03
Оценка:
Увы но это так
https://stackoverflow.com/questions/44666169/initializer-list-and-structured-bindings-deduction-ambiguity-in-c17

Насколько я понимаю в теории можно специализировать std::get для initalizer_list и тогда код соберётся
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[10]: range based for - первый/последний?
От: andrey.desman  
Дата: 14.03.19 17:41
Оценка:
Здравствуйте, B0FEE664, Вы писали:

AD>>A std::initializer_list object is automatically constructed when: a braced-init-list is bound to auto, including in a ranged for loop

BFE>А это наш случай? У нас structured binding, а не bound to auto. Разве это одно и тоже?
Наш. См. ниже.

AD>>Это copy-list-initialization и там не initializer_list, а braced-init-list.

BFE>Что говорит нам о том, что типы не обязаны быть одинаковыми. initializer_list не нужен.
Тут не обязаны, тут не нужен.

BFE>С того, что ничему не противоречит.

Противоречит описанию.

AD>>В expression вообще запятой быть не положено, а когда ты = убираешь, то оно спотыкается уже на этом.

BFE>Не должно быть оператора запятая. Где у меня операторы?
У выражения не может быть не оператора ",", поэтому там именно оператор.

AD>>Твой изначальный код — это примерно следующее:

AD>>auto list = { i, c }; // initalizer_list, fail
BFE>initalizer_list отсутствует в structured binding описании.

Ему там и не надо быть. Если expression не массив, то.

Otherwise e is defined as if by using its name instead of [ identifier-list ] in the declaration.


Т.е.
auto [a, b] = {1,2,3};
// =>
auto e = {1,2,3}; // initializer_list
...


BFE>Предположим, что всё так, как вы пишите. Тогда получается, что это практически безполезная фича языка. Жаль, могла получиться красивая конструкция.


Почему бесполезная? Потому что присваивания параллельными пачками нельзя делать, не написав std::tuple?
Re[11]: range based for - первый/последний?
От: B0FEE664  
Дата: 14.03.19 17:44
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>Насколько я понимаю в теории можно специализировать std::get для initalizer_list и тогда код соберётся

Там сказано, что можно просто написать:

 const auto [x, y] = std::forward_as_tuple(a, b);

Жить можно, но мне не нравится. Нет краткости.
И каждый день — без права на ошибку...
Re[11]: range based for - первый/последний?
От: B0FEE664  
Дата: 14.03.19 17:52
Оценка:
Здравствуйте, andrey.desman, Вы писали:

AD>Почему бесполезная? Потому что присваивания параллельными пачками нельзя делать, не написав std::tuple?

Почему С++ не называется "с = с + 1"?
Вот и тут так же.
И каждый день — без права на ошибку...
Re[12]: range based for - первый/последний?
От: rg45 СССР  
Дата: 14.03.19 17:56
Оценка: :)
Здравствуйте, B0FEE664, Вы писали:

BFE>Почему С++ не называется "с = с + 1"?


Потому, что "с = с + 1" — это ++С

А С++ — это "(c = c + 1, c — 1)".
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 14.03.2019 18:02 rg45 . Предыдущая версия .
Re[12]: range based for - первый/последний?
От: _NN_ www.nemerleweb.com
Дата: 14.03.19 20:07
Оценка:
using fat = ::std::forward_as_tuple;

Или хочется новый синтаксис ввести в язык ?
Можно попытаться через stdcpp.ru
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[13]: range based for - первый/последний?
От: B0FEE664  
Дата: 14.03.19 21:57
Оценка: :)
Здравствуйте, rg45, Вы писали:

BFE>>Почему С++ не называется "с = с + 1"?

R>Потому, что "с = с + 1" — это ++С

Connoisseurs of C semantics find C++ inferior to ++C.


отсюда.
И каждый день — без права на ошибку...
Re[13]: range based for - первый/последний?
От: B0FEE664  
Дата: 14.03.19 22:26
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>
using fat = ::std::forward_as_tuple;

_NN>Или хочется новый синтаксис ввести в язык ?
Так в том-то и дело, что синтаксис новый добавили, но с несколько неожиданным поведением.

_NN>Можно попытаться через stdcpp.ru

Сначало можно тут обсудить.

Например, можно было бы ввести новый оператор, который никакой роли сам в языке по себе не играет, но который можно перегрузить для любого, не только пользовательского типа.

float operator =>(MyVariant from, float to)
{
  if ( ! from.IsFloat() )
    throw std::bad_cast();
        
  to = from.get<float>();

  return to;
}

int operator =>(float from, int to)
{
  if ( static_cast<float>(static_cast<int>(from)) != from )
    throw std::bad_cast();
        
  to = static_cast<int>(from);

  return to;
}


Использование:
MyVariant my(1.2f);
float my => f;
int f => n;

float x = 1.f;
o => x;
И каждый день — без права на ошибку...
Re: range based for - первый/последний?
От: Alexey F  
Дата: 15.03.19 18:05
Оценка:
Здравствуйте, Marty, Вы писали:

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

Для C++17 что-то вроде такого: http://reedbeta.com/blog/python-like-enumerate-in-cpp17/

Тогда:
std::size_t const size = std::size( data );
for( auto [ i, v ] = enumerate( data ) ) {
    if( i == 0 ) {} // первый элемент (или единственный, если size( data ) == 1)
    else if( i + 1 == size ) {} // последний элемент
    else {} // между первым и последним
}


Для вывода с запятыми:
for( auto [ i, v ] : enumerate( data ) ) {
    if( i != 0 ) {
        std::cout << ", ";
    }
    std::cout << v;
}
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.