BOOST_FOREACH & шаблоны без typedef - PullRequest
10 голосов
/ 11 ноября 2009

Когда я работаю с BOOST_FOREACH, не возникает проблем с простыми шаблонами в качестве вектора. Но когда я пытаюсь перебрать карту> например, мне нужно ввести определение типа элемента.

Есть ли обходной путь?

Ответы [ 4 ]

12 голосов
/ 11 ноября 2009

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

Вы также можете объявить переменную перед циклом, см. Документация .

std::map<int, double> my_map;

//1)
typedef std::pair<int, double> MyPair;
BOOST_FOREACH(MyPair p, my_map) { ... }

//2)
std::pair<int, double> p;
BOOST_FOREACH(p, my_map) { ... }

Edit:

Есть еще одно осложнение, в частности с std::map: value_type - это не std::pair<Key, Value>, а std::pair<const Key, Value>.

Следовательно, если вы используете typedef, более правильный способ (и единственный способ, если вы хотите использовать ссылку в цикле foreach) - это использовать

typedef std::pair<const int, double> MyPair;
//or
typedef std::map<int, double>::value_type MyPair;

BOOST_FOREACH(MyPair& ref, my_map) { ... }

Однако это не сработает, если вы захотите использовать переменную, объявленную перед циклом, поскольку вы не можете назначить экземпляр std::pair<const int, double> позже (не можете назначить поле const), в этом случае вы можно использовать только pair<int, double>, как показывает ручной буст.

8 голосов
/ 14 января 2012

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

std::map<int, double> my_map;
int key;
double value;
BOOST_FOREACH(boost::tie(key, value), my_map) { ... }

Просто примечание, запятые будут работать здесь, потому что круглые скобки расположены вокруг ключа и значения. Препроцессор понимает только запятые и круглые скобки (а c99 требует, чтобы он также понимал кавычки). Таким образом, он не может разобрать <> в std::pair<int, double>. Однако мы можем использовать скобки, чтобы помочь препроцессору. Например, если у нас есть функция, которая возвращает контейнер, который вызывается так:

BOOST_FOREACH(int i, foo<int, int>()) { ... } //This won't compile

Итак, мы можем поместить круглые скобки вокруг выражения, и это поможет препроцессору:

BOOST_FOREACH(int i, (foo<int, int>())) { ... } //This will compile

Однако в случае карты мы не можем поместить круглые скобки вокруг объявления (потому что это не выражение). Так что это не сработает:

BOOST_FOREACH((std::pair<int, double> p), my_map) { ... } //This won't work

Потому что он будет преобразован в нечто подобное (std::pair<int, double> p) = *it, и это, конечно, неверно в C ++. Но использование галстука сработает:

BOOST_FOREACH(tie(key, value), my_map) { ... } //This will work

Нам просто нужно объявить ключ и значение вне цикла (как показано выше). Плюс, это может заставить цикл иметь более значимые имена. Вы можете написать key вместо p.first и value вместо p.second.

6 голосов
/ 17 ноября 2009

BOOST_FOREACH_PAIR - еще один вариант, который хорошо работает по нашему опыту:

http://lists.boost.org/Archives/boost/2009/09/156345.php

http://lists.boost.org/Archives/boost/2009/09/156366.php

2 голосов
/ 03 февраля 2013

Это может быть так просто:

BOOST_FOREACH(auto& p, my_map) { ... }

Используя стандарт C ++ 11, auto похож на var в C #, он будет делать

BOOST_FOREACH(std::pair<int, double>& p, my_map) { ... }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...