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

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

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: HowTo: Цикл foreach - будьте аккуратны, Qt понимает только простые типы  (Прочитано 43457 раз)
xintrea
Moderator
Супер активный житель
*****
Offline Offline

Сообщений: 754



Просмотр профиля WWW
« : Октябрь 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);
}
« Последнее редактирование: Октябрь 15, 2010, 02:19 от xintrea » Записан

Собираю информацию по крупицам
http://webhamster.ru
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3257


Просмотр профиля
« Ответ #1 : Октябрь 14, 2010, 14:41 »

Мок не имеет отношения к форычу. Это чистые макросы/темплейты.
Записан
xintrea
Moderator
Супер активный житель
*****
Offline Offline

Сообщений: 754



Просмотр профиля WWW
« Ответ #2 : Октябрь 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.
« Последнее редактирование: Октябрь 14, 2010, 14:58 от xintrea » Записан

Собираю информацию по крупицам
http://webhamster.ru
Vass
Гость
« Ответ #3 : Октябрь 14, 2010, 15:57 »

Добавлю, что это касается вообще всех Qt'шных макросов, например, на собственном опыте убедился, что тип с запятой не принимается в Q_DECLARE_METATYPE.
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3257


Просмотр профиля
« Ответ #4 : Октябрь 14, 2010, 16:06 »

xintrea
Интересно, а как же тогда форыч работает в cmake, где сорцы для мока указываются руками? И даже если нет ни 1го мокнутого файла, то форыч работает. Хз, откуда вы взяли про связь мока и форыча - смотрите объявление макросов, там нет никаких заглушек, которые бы вставлял мок (да и куда он их будет вставлять??)
Записан
xintrea
Moderator
Супер активный житель
*****
Offline Offline

Сообщений: 754



Просмотр профиля WWW
« Ответ #5 : Октябрь 14, 2010, 18:45 »

Интересно, а как же тогда foreach работает в cmake, где сорцы для MOC указываются руками? И даже если нет ни одного MOC-файла, то foreach работает. Хз, откуда вы взяли про связь MOC и foreach - смотрите объявление макросов, там нет никаких заглушек, которые бы вставлял MOC (да и куда он их будет вставлять??)

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

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

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

Собираю информацию по крупицам
http://webhamster.ru
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3257


Просмотр профиля
« Ответ #6 : Октябрь 31, 2010, 11:56 »

Учитывайте, что moc не может "править" сорцы, в отличие от препроцессора - он же фактически изменяет .cpp, тогда как moc создает свой файл и в нем срет. Так что это технологически сложнее.
Записан
zenden
Гость
« Ответ #7 : Октябрь 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
« Последнее редактирование: Октябрь 31, 2010, 13:30 от zenden » Записан
ритт
Гость
« Ответ #8 : Апрель 14, 2011, 20:28 »

Добавлю, что это касается вообще всех Qt'шных макросов, например, на собственном опыте убедился, что тип с запятой не принимается в Q_DECLARE_METATYPE.

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

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

Сообщений: 3257


Просмотр профиля
« Ответ #9 : Апрель 14, 2011, 21:40 »

Константин
Ты меня уже приучил почти:)
Записан
blood_shadow
Гость
« Ответ #10 : Апрель 15, 2011, 11:13 »

оператор continue коректно работает внутри qt-шного foreach?
Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #11 : Апрель 15, 2011, 11:23 »

Да.
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
artiom_kh
Гость
« Ответ #12 : Март 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) {}
 
?
Записан
mutineer
Гость
« Ответ #13 : Март 06, 2012, 12:05 »

Удивительное рядом - если начать наконец-то читать документацию (а не что вы там делаете с ней), то там можно найти такие строки
Цитировать
За исключением типа данных, содержащего запятую (например, QPair<int, int>), переменная, используемая для перебора элементов контейнера может быть определена внутри выражения foreach:
Записан
Bepec
Гость
« Ответ #14 : Март 06, 2012, 12:07 »

некропостеры блин, успокойтесь Веселый
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


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