Это несколько «зло», но оно спасло нас от многих ошибок.
(Обновление, спасибо комментарию @ Ricky65 за то, что он привел меня сюда.) C ++ 11 имеет основанный на диапазоне цикл for , который намного превосходит это, если ваш компилятор его поддерживает; мы все еще работаем с некоторыми действительно старыми компиляторами.
#define FOREACH(iter,stlContainer) \
for ( typeof(stlContainer.begin()) iter = stlContainer.begin(), \
iter##End_Cached = stlContainer.end(); \
iter != iter##End_Cached; \
++iter )
(Дальнейшее обновление, спасибо разработчикам Boost.) Он основан на более сложном, но более способном макросе BOOST_FOREACH
, но имеет преимущество в том, что для небольших случаев гораздо проще переходить в отладочных сборках, а не требуется небольшая куча заголовков надстроек (в некоторых кодовых базах / группах это verboten).
Использование std::for_each
обычно предпочтительнее, но имеет ряд недостатков:
- пользователи должны много знать о взаимодействиях между
bind1st
/ bind2nd
/ ptr_fun
/ mem_fun
, чтобы эффективно использовать его для нетривиального "посещения" - повышение устраняет многие из этих проблем, но не каждый имеет или знает повышение
- пользователям может потребоваться предоставить свой отдельный функтор (обычно структуру) только для одной точки использования; указанные структуры не могут быть объявлены внутри функции, окружающей цикл, что приводит к «нелокальности» связанного кода - в некоторых случаях он не читает, а не имеет логики в соответствии с потоком остальной функции
- это не всегда красиво встроено, в зависимости от компилятора
Макрос FOREACH, как указано выше, предоставляет несколько вещей:
- как и
std::for_each
, вы не ошибетесь в граничных тестах (без повторов до конца и т. Д.)
- будет использовать
const_iterators
над постоянными контейнерами
Обратите внимание, что для этого требуется несколько нестандартное расширение "typeof".
Типичное использование может быть:
list< shared_ptr< Thing > > m_memberList;
// later
FOREACH( iter, m_memberList )
{
if ( (*iter)->getValue() < 42 ) {
doSomethingWith( *iter );
}
}
Я не совсем доволен этим макросом, но он здесь неоценим, особенно для программистов, не имеющих большого опыта в разработке с поддержкой STL.
(Пожалуйста, не стесняйтесь указывать плюсы / минусы / недостатки, я обновлю ответ.)