Russian Qt Forum
Ноябрь 24, 2024, 18:19 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2 3 ... 6   Вниз
  Печать  
Автор Тема: Итераторы  (Прочитано 32158 раз)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« : Январь 28, 2021, 13:04 »

Добрый день

Есть большой класс, и в нем
Код
C++ (Qt)
struct CBigClass {
...
QList<CData> mData;
QSet<CData *> mSelection;
...
};
И есть метод
Код
C++ (Qt)
void CBigClass::SomeMethod( void )
{
 ..
 for (auto & data : mData) {
  ...
 }
}
С довольно содержательным телом цикла, переписывать его явно не хочется. (как и делать из тела метод)

Требуется сделать так чтобы можно было крутить цикл и по selection,
Код
C++ (Qt)
void CBigClass::SomeMethod2( void )
{
 ..
 for (auto it : mSelection) {
  ...
 }
}
Но конечно без копирования содержательной части (тела цикла).
Как это сделать итераторами или чем еще (в "современном С++") ?

Спасибо
« Последнее редактирование: Январь 28, 2021, 13:13 от Igors » Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #1 : Январь 28, 2021, 14:15 »

Ш - шаблоны
Записан
RedDog
Частый гость
***
Offline Offline

Сообщений: 221


Просмотр профиля
« Ответ #2 : Январь 28, 2021, 16:53 »

Код:
for (auto it = std::begin(container); it != std::end(container); ++it)
Останется только container через шаблон передать
Давно не видел void в скобочках.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #3 : Январь 29, 2021, 08:38 »

Код:
for (auto it = std::begin(container); it != std::end(container); ++it)
Останется только container через шаблон передать
Давно не видел void в скобочках.
Так контейнеры имеют разные типы эл-тов, как бум извращаться?

Конечно "цена вопроса" невелика, есть неск приемлемых решений. Самое простое - конвертировать контейнеры в вектор указателей std::vector<CData *>. Ну будет какой-то оверхед, но не смертельный. Можно и просто "заткнуть" парой-тройкой  if'ов, напр
Код
C++ (Qt)
void CBigClass::SomeMethod( bool useSelection )
{
 ..
 int limit = useSelection ? mSelection.size() : mData.size();
 auto dataIt = mData.begin();  
 auto selIt = mSelection.begin();  
 for (int i = 0; i < limit; ++i) {
   CData * dataPtr;
   if (useSelection) {
      dataPtr = *selIt;
      ++selIt;
   }
   else {
      dataPtr = &(*dataIt);
      ++dataIt;
   }
 
  ...
 }
}
Это конечно явно "не общий случай", а вдруг надо еще какой-то контейнер парить? С др стороны пока не видно откуда ему взяться, все CData во владении CBigClass

Просто бросается в глаза что нужно "итерироваться" причем всяко-разно. Нет ли чего-нибудь модного/элегантного ?
Записан
RedDog
Частый гость
***
Offline Offline

Сообщений: 221


Просмотр профиля
« Ответ #4 : Январь 29, 2021, 09:53 »

std::advance
std::next
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #5 : Январь 29, 2021, 11:18 »

std::advance
std::next
Не вижу как это поможет разрулить разные типы эл-тов. Если с темплейтами то может так "подмазать"
Код
C++ (Qt)
template<class Iter>
CData & DataRef( Iter & it )
{
 return *it;
}
 
CData & DataRef( QSet<CData *>::iterator & it )
{
 return *(*it);
}
И вызывать
Код
C++ (Qt)
template<class Container>
void CBigClass::SomeMethod( Container & container )
{
 ...
 for (auto it = container.begin(); it != container.emd(); ++it) {
  CData & data = DataRef(it);
  ...
 }
}
Попинайте
Записан
RedDog
Частый гость
***
Offline Offline

Сообщений: 221


Просмотр профиля
« Ответ #6 : Январь 29, 2021, 11:23 »

SomeMethod сделать шаблонным, шаблоном туда передавать контейнер


Код:
template<typename T>
void iterateContainer(const T& t)
{
    for (auto it = std::begin(t); it != std::end(t); ++it)
    {
        // do something
    }
}

void testIterate()
{
    std::vector<int> vec;
    std::list<int> list;
    std::map<int, std::string> map;
    iterateContainer(vec);
    iterateContainer(list);
    iterateContainer(map);
}
« Последнее редактирование: Январь 29, 2021, 11:29 от RedDog » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #7 : Январь 29, 2021, 12:37 »

Код:
template<typename T>
void iterateContainer(const T& t)
{
    for (auto it = std::begin(t); it != std::end(t); ++it)
    {
        // do something
    }
}
}
Do something with what? Улыбающийся Как я использую it ? Ведь рвзыменование *it даст разные типы для разных входных контейнеров.
Записан
RedDog
Частый гость
***
Offline Offline

Сообщений: 221


Просмотр профиля
« Ответ #8 : Январь 29, 2021, 13:14 »

Касательно начала темы, там только 2 типа, CData и CData*
отделить одно от другого можно через std::is_pointer
так же можно сравнить с нужным типом через std::is_same
« Последнее редактирование: Январь 29, 2021, 13:16 от RedDog » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #9 : Январь 29, 2021, 16:20 »

Касательно начала темы, там только 2 типа, CData и CData*
отделить одно от другого можно через std::is_pointer
так же можно сравнить с нужным типом через std::is_same
Тогда зачем было заявлять общность (темплейт) если латаем? Залатать и так можно. Да и "отделить" с помощью std::is_pointer (или std::is_same) не так уж легко, просто "if" не получится, нужно городить что-то типа std::enable_if  (помню смутно). Подозреваю что латка получится никак не меньше чем бесхитростная выше.

Повторюсь, дело не в том что, мол, не знаю как решать, "памагите" Улыбающийся Но хочется сделать вккуратно, а не развешивать сопли.
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #10 : Январь 29, 2021, 16:26 »

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

Это прекрасное решение и всем, кто в дальнейшем будет читать этот код, все сразу будет понятно. Улыбающийся
Код
C++ (Qt)
void CBigClass::SomeMethod( bool useSelection )
{
 ..
 int limit = useSelection ? mSelection.size() : mData.size();
 auto dataIt = mData.begin();  
 auto selIt = mSelection.begin();  
 for (int i = 0; i < limit; ++i) {
   CData * dataPtr;
   if (useSelection) {
      dataPtr = *selIt;
      ++selIt;
   }
   else {
      dataPtr = &(*dataIt);
      ++dataIt;
   }
 
  ...
 }
}
Записан
RedDog
Частый гость
***
Offline Offline

Сообщений: 221


Просмотр профиля
« Ответ #11 : Январь 29, 2021, 17:34 »

https://en.cppreference.com/w/cpp/types/add_pointer
Опять не?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #12 : Январь 30, 2021, 10:00 »

Ну вот, сейчас начнется
Цитировать
Уже столько вариантов предложили, а ему все не так!
Улыбающийся

Но давайте все-таки посмотрим "что предложили". Ведь вся эта хренотень (is_pointer, add_pointer и.т.п.) - вовсе не обычные ф-ции которыми можно спокойно воспользоваться. Как я понимаю, они позволяют сделать темплейты что будут корректно вызываться для указателя и нет, но их надо еще делать, а как? (навскидку я не напишу)

Во-вторых, как-то "не концептуально". Объявление template означает что можем подавать что угодно, во всяком случае - многое. В этом и кайф этого угребочного мета-программирования. А сами обеспечиваем лишь 2 варианта: ссылка и указатель. Потребуется напр по значениям мапы - и все. Да, конкретно для данной задачи нужны только 2 варианта, но если пердлагаем "общность" - то надо ее поддерживать
Записан
RedDog
Частый гость
***
Offline Offline

Сообщений: 221


Просмотр профиля
« Ответ #13 : Февраль 01, 2021, 09:20 »

Объявление template означает что можем подавать что угодно, во всяком случае - многое.
Нет template говорит о том, что обработка переданных аргументов будет одинакова для разных типов.
А внутренняя реализация обработки зависит от разработчика.
Чем сильнее различается АПИ аргументов, тем больше будет геморроя при реализации.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #14 : Февраль 01, 2021, 11:09 »

Может лучше нацелить темплейт(ы) не на итератор, а на *итератор, т.е. разыменованную ссылку
Код
C++ (Qt)
template<class T>
CData & DataRef( T & ref ) {  return ref; }
 
CData & DataRef( CData  *& refPtr ) { return *refPtr; }
Выглядит гораздо проще чем is_pointer и.т.п. (как то писать - хз, а покрывает лишь один случай)

Однако же... как переменчива мода... Раньше страсти кипели, там всякие вариадики, SFINAE (если я правильно помню это слово), traits и еще бог весть что. А сейчас - та вроде никому это и не интересно. Мда...
Записан
Страниц: [1] 2 3 ... 6   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.329 секунд. Запросов: 22.