Russian Qt Forum

Qt => Уроки и статьи => Тема начата: xintrea от Октябрь 14, 2010, 14:30



Название: HowTo: Цикл foreach - будьте аккуратны, Qt понимает только простые типы
Отправлено: xintrea от Октябрь 14, 2010, 14:30
Недавно мне пришлось писать код, который обрабатывает структуру контейнеров, вложенных друг в друга. Структура была вот такая:

Код
C++ (Qt)
QList< QMap<QString, QString> > branch;

Мне нужно было пробежать по списку QList, и распечатать каждую пару ключ-значение для QMap.

Заглянув в документацию, я написал следующий код:

Код
C++ (Qt)
// Пробегается QList
foreach(QMap<QString, QString> current_branch, branch)
{
 qDebug() << "Branch data:";
 
 // Пробегается QMap, для извлечения пар ключ-значение
 foreach(QString field_name, current_branch.keys())
  qDebug() << field_name << ":" << current_branch.value(field_name);
}

Как оказалось, скомпилировать данный код невозможно. Выдается следующая ошибка:

Цитировать
error: macro "Q_FOREACH" passed 3 arguments, but takes just 2

То есть, в строке "foreach(QMap<QString, QString> current_branch, branch)" запятая между QString воспринимается как запятая для разделения параметров, хотя на деле является запятой в описании типа.

Решение в такой ситуации следующее - описать новый тип, который "вберёт" в себя тип, в котором есть запятая, и в цикле foreach использовать этот новый тип. Вот так:

Код
C++ (Qt)
// Пробегается QList
typedef QMap<QString, QString> branch_type;
foreach(branch_type current_branch, branch)
{
 qDebug() << "Branch data:";
 
 // Пробегается QMap, для извлечения пар ключ-значение
 foreach(QString field_name, current_branch.keys())
  qDebug() << field_name << ":" << current_branch.value(field_name);
}


Название: Re: [HOWTO] Цикл foreach: будьте аккуратны, MOC понимает только простые типы
Отправлено: Авварон от Октябрь 14, 2010, 14:41
Мок не имеет отношения к форычу. Это чистые макросы/темплейты.


Название: Re: [HOWTO] Цикл foreach: будьте аккуратны, MOC понимает только простые типы
Отправлено: xintrea от Октябрь 14, 2010, 14:53
Мок не имеет отношения к форычу. Это чистые макросы/темплейты.

Очень даже имеет, ибо использование foreach всеравно проходит через MOC - "Q_FOREACH. This macro is available even when no_keywords is specified using the .pro file's CONFIG variable." Обработкой .pro занимается qmake, используя MOC для преобразования/дополнения кода, и то, что foreach обрабатывается только C/С++ - шными механизмами макросов и темплейтов, целиком и полностью лежит на MOC. Тролли могли бы написать и более корректное раскрытие нестандартного ключевого слова foreach.


Название: Re: [HOWTO] Цикл foreach: будьте аккуратны, MOC понимает только простые типы
Отправлено: Vass от Октябрь 14, 2010, 15:57
Добавлю, что это касается вообще всех Qt'шных макросов, например, на собственном опыте убедился, что тип с запятой не принимается в Q_DECLARE_METATYPE.


Название: Re: [HOWTO] Цикл foreach: будьте аккуратны, MOC понимает только простые типы
Отправлено: Авварон от Октябрь 14, 2010, 16:06
xintrea
Интересно, а как же тогда форыч работает в cmake, где сорцы для мока указываются руками? И даже если нет ни 1го мокнутого файла, то форыч работает. Хз, откуда вы взяли про связь мока и форыча - смотрите объявление макросов, там нет никаких заглушек, которые бы вставлял мок (да и куда он их будет вставлять??)


Название: Re: [HOWTO] Цикл foreach: будьте аккуратны, MOC понимает только простые типы
Отправлено: xintrea от Октябрь 14, 2010, 18:45
Интересно, а как же тогда foreach работает в cmake, где сорцы для MOC указываются руками? И даже если нет ни одного MOC-файла, то foreach работает. Хз, откуда вы взяли про связь MOC и foreach - смотрите объявление макросов, там нет никаких заглушек, которые бы вставлял MOC (да и куда он их будет вставлять??)

Скажу по-другому.

В данный момент foreach трансформируется в C/C++ код только макросами, входящими в состав Qt, от этого и проблема. По хорошему, цикл foreach должен обрабатывать MOC, причем так, чтобы небыло спотыканий на запятых, входящих в описание типа используемой переменной.

Согласен, что название топика неудачное, ща подумаю на что исправить.


Название: Re: HowTo: Цикл foreach - будьте аккуратны, Qt понимает только простые типы
Отправлено: Авварон от Октябрь 31, 2010, 11:56
Учитывайте, что moc не может "править" сорцы, в отличие от препроцессора - он же фактически изменяет .cpp, тогда как moc создает свой файл и в нем срет. Так что это технологически сложнее.


Название: Re: HowTo: Цикл foreach - будьте аккуратны, Qt понимает только простые типы
Отправлено: zenden от Октябрь 31, 2010, 13:23
Код
C++ (Qt)
#define HAS_COMMAS(...) __VA_ARGS__
 
QList< QMap<QString, QString> > branch;
 
foreach(HAS_COMMAS(QMap<QString, QString> current_branch), branch)
{
//....
}
 

проверял под mingw


Название: Re: [HOWTO] Цикл foreach: будьте аккуратны, MOC понимает только простые типы
Отправлено: ритт от Апрель 14, 2011, 20:28
Добавлю, что это касается вообще всех Qt'шных макросов, например, на собственном опыте убедился, что тип с запятой не принимается в Q_DECLARE_METATYPE.

добавлю, что это вообще не касается Qt'шных макросов, но макросов как таковых. для препроцессора С это норма и в книгах часто можно встретить упоминание об этом...
перекладывать данную задачу на мок - имхо, бред.

и просто не могу пройти мимо
> foreach(branch_type current_branch, branch) // больше сущностей хороших и всяких (а также ненужных)!
найдите отличия с
> foreach(const branch_type &current_branch, branch)


Название: Re: HowTo: Цикл foreach - будьте аккуратны, Qt понимает только простые типы
Отправлено: Авварон от Апрель 14, 2011, 21:40
Константин
Ты меня уже приучил почти:)


Название: Re: HowTo: Цикл foreach - будьте аккуратны, Qt понимает только простые типы
Отправлено: blood_shadow от Апрель 15, 2011, 11:13
оператор continue коректно работает внутри qt-шного foreach?


Название: Re: HowTo: Цикл foreach - будьте аккуратны, Qt понимает только простые типы
Отправлено: Пантер от Апрель 15, 2011, 11:23
Да.


Название: Re: HowTo: Цикл foreach - будьте аккуратны, Qt понимает только простые типы
Отправлено: artiom_kh от Март 06, 2012, 11:54
Недавно мне пришлось писать код, который обрабатывает структуру контейнеров, вложенных друг в друга. Структура была вот такая:

Код
C++ (Qt)
QList< QMap<QString, QString> > branch;

Мне нужно было пробежать по списку QList, и распечатать каждую пару ключ-значение для QMap.

Заглянув в документацию, я написал следующий код:

Код
C++ (Qt)
// Пробегается QList
foreach(QMap<QString, QString> current_branch, branch)
{
 qDebug() << "Branch data:";
 
 // Пробегается QMap, для извлечения пар ключ-значение
 foreach(QString field_name, current_branch.keys())
  qDebug() << field_name << ":" << current_branch.value(field_name);
}

Как оказалось, скомпилировать данный код невозможно. Выдается следующая ошибка:

Цитировать
error: macro "Q_FOREACH" passed 3 arguments, but takes just 2

То есть, в строке "foreach(QMap<QString, QString> current_branch, branch)" запятая между QString воспринимается как запятая для разделения параметров, хотя на деле является запятой в описании типа.

Решение в такой ситуации следующее - описать новый тип, который "вберёт" в себя тип, в котором есть запятая, и в цикле foreach использовать этот новый тип. Вот так:

Код
C++ (Qt)
// Пробегается QList
typedef QMap<QString, QString> branch_type;
foreach(branch_type current_branch, branch)
{
 qDebug() << "Branch data:";
 
 // Пробегается QMap, для извлечения пар ключ-значение
 foreach(QString field_name, current_branch.keys())
  qDebug() << field_name << ":" << current_branch.value(field_name);
}


а вот так:
Код
C++ (Qt)
QList< QMap<QString, QString> > branch;
 
// Пробегается QList
foreach(const QMap<QString, QString>& current_branch, branch) {}
 
?


Название: Re: HowTo: Цикл foreach - будьте аккуратны, Qt понимает только простые типы
Отправлено: mutineer от Март 06, 2012, 12:05
Удивительное рядом - если начать наконец-то читать документацию (а не что вы там делаете с ней), то там можно найти такие строки
Цитировать
За исключением типа данных, содержащего запятую (например, QPair<int, int>), переменная, используемая для перебора элементов контейнера может быть определена внутри выражения foreach:


Название: Re: HowTo: Цикл foreach - будьте аккуратны, Qt понимает только простые типы
Отправлено: Bepec от Март 06, 2012, 12:07
некропостеры блин, успокойтесь :D


Название: Re: HowTo: Цикл foreach - будьте аккуратны, Qt понимает только простые типы
Отправлено: mutineer от Март 06, 2012, 12:07
некропостеры блин, успокойтесь :D

Добро пожаловать в наши ряды;)


Название: Re: HowTo: Цикл foreach - будьте аккуратны, Qt понимает только простые типы
Отправлено: kambala от Июнь 05, 2012, 15:51
на всякий случай спрошу (pvs-studio ругает): если вторым параметром в foreach использовать, например, результат вызова метода/функции, то этот вызов будет производиться лишь 1 раз, да?


Название: Re: HowTo: Цикл foreach - будьте аккуратны, Qt понимает только простые типы
Отправлено: Пантер от Июнь 05, 2012, 15:52
Да, значение копируется.


Название: Re: HowTo: Цикл foreach - будьте аккуратны, Qt понимает только простые типы
Отправлено: qate от Январь 16, 2015, 08:38
QMAKE_CXXFLAGS += -std=c++11

Код
foreach(auto current_branch, branch)
{
...
}
 


Название: Re: HowTo: Цикл foreach - будьте аккуратны, Qt понимает только простые типы
Отправлено: kambala от Январь 16, 2015, 13:46
с 11 уж можно и
Код
C++ (Qt)
for (/*const*/ auto &x : array) {}