Навеяно словами WolfHound'a в ветке
C++/CLI PDC presentationАвтор: alexkro
Дата: 01.11.03
Вот создал макрос для перебора всех элементов контейнера, стараясь как можно больше приблизиться к
приведенному там синтаксису.
В результате организация цикла выглядит примерно так: FOR_EACH(int& i, the_container)
Определение макроса:
namespace _foreach
{
class base {};
template <typename T>
struct wrapper : public base
{
mutable T wrapped;
wrapper(const T& t): wrapped(t) {}
};
template <typename T>
wrapper<T> wrap(const T& t)
{ return t; }
template <typename T>
T& unwrap(const base& b, const T&)
{ return static_cast<const wrapper<T>&>(b).wrapped; }
} // end namespace foreach
#define FOR_EACH_(Decl, First, Last) \
if (false) {} else /*VC6 for-init-scope bug workaround*/ \
for (const _foreach::base &_fe_cur = _foreach::wrap(First), &_fe_last = _foreach::wrap(Last); \
_foreach::unwrap(_fe_cur, First) != _foreach::unwrap(_fe_last, Last); \
++_foreach::unwrap(_fe_cur, First)) \
if (bool _fe_once = false) {} else \
for (Decl = *_foreach::unwrap(_fe_cur, First); !_fe_once; _fe_once = true) \
// end macro
#define FOR_EACH(Decl, Cont) FOR_EACH_(Decl, (Cont).begin(), (Cont).end())
Использование:
#include <vector>
#include <set>
#include <string>
#include <iostream>
using namespace std;
int main(int argc, const char* argv[])
{
std::set<std::string> str_set;
str_set.insert("red");
str_set.insert("green");
str_set.insert("blue");
FOR_EACH(const string& s, str_set) cout << s << endl;
std::vector<short> short_vec;
short_vec.push_back(-2);
short_vec.push_back(-1);
short_vec.push_back(0);
FOR_EACH(short& i, short_vec) ++i;
FOR_EACH(int i, short_vec)
{
if (i >= 0 && i < argc) cout << argv[i] << endl;
else cout << i << endl;
}
return 0;
}
Вижу в этом решении следующие проблемы (не считая проблем идеологического характера):
1. break работает точно так же, как continue, а хотелось бы полного соответствия семантике цикла.
2. Постоянные ненужные вызовы container.begin() и container.end(), служащие только для определения того, к какому типу надо приводить базовую ссылку. Но проверка asm-листинга VC6 для этого примера показала что все эти вызовы выкидывются оптимизатором. Для VC7.1 даже проверять не стал.
Если бы имелся оператор typeof, то такой проблемы не возникло бы вообще.
3. Ну и конечно же неудобства при отладке такого макроса.
Несмотря на все это я уже второй день пользую FOR_EACH и FOR_EACH_ и очень доволен.
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн