Есть ли проблемы с этой реализацией макроса foreach?
В расширении Intel Cilk Plus есть это ключевое слово cilk_for (или, собственно, _Cilk_for). Это как ключевое слово для, но более ограниченное и его итерации выполняются параллельно. Я написал вспомогательный макрос в духе BOOST_FOREACH, который использует cilk_for для внутреннего использования. Вы видите какие-либо проблемы со следующей реализацией?
#pragma once
#include <iterator>
#include <boost/preprocessor/cat.hpp>
#include <cilk/cilk.h>
#define cilk_foreach(_decl_var_, _expr_range_) \
CILK_FOREACH_I(_decl_var_, _expr_range_, __COUNTER__)
#define CILK_FOREACH_I(_decl_var_, _expr_range_, _id_) \
CILK_FOREACH_II(_decl_var_, \
_expr_range_, \
BOOST_PP_CAT(_range_3s236dw221GyVcf46_, _id_), \
BOOST_PP_CAT(_end_5Y60u42bIp7DZd88f2c_, _id_), \
BOOST_PP_CAT(_itr_6V970q8n4Etv0i8bf50_, _id_), \
BOOST_PP_CAT(_continue_4rtWH641r5cXqU_, _id_))
#define CILK_FOREACH_II(_decl_var_, _expr_range_, _range_, _end_, _itr_, _cont_) \
auto&& _range_ = _expr_range_; \
auto _end_ = std::end(_range_); \
\
cilk_for (auto _itr_ = std::begin(_range_); _itr_ != _end_; ++_itr_) \
if (auto _cont_ = true) \
for (_decl_var_ = *_itr_; _cont_; _cont_ = false)
Вы бы использовали это так:
std::vector<int> values (10);
cilk_foreach (auto& value , values)
{
value += 123;
}
РЕДАКТИРОВАТЬ
template <typename T>
struct Wrap
{
T& data;
explicit Wrap(T&& data)
: data (data)
{}
operator bool() const
{
return true;
}
};
template <typename T>
Wrap<T> wrap(T&& data)
{
return Wrap<T>(std::forward<T>(data));
}
#define cilk_foreach(_decl_var_, _expr_range_) \
CILK_FOREACH_I(_decl_var_, _expr_range_, __COUNTER__)
#define CILK_FOREACH_I(_decl_var_, _expr_range_, _id_) \
\
CILK_FOREACH_II(_decl_var_, \
_expr_range_, \
BOOST_PP_CAT(_range_3s236dw221GyVcf46_, _id_), \
BOOST_PP_CAT(_itr_6V970q8n4Etv0i8bf50_, _id_), \
BOOST_PP_CAT(_continue_4rtWH641r5cXqU_, _id_))
#define CILK_FOREACH_II(_decl_var_, _expr_range_, _range_, _itr_, _cont_) \
\
if (auto _range_ = wrap(_expr_range_)) \
cilk_for (auto _itr_ = std::begin(_range_.data); \
_itr_ != std::end (_range_.data); \
++_itr_) \
if (auto _cont_ = true) \
for (_decl_var_ = *_itr_; _cont_; _cont_ = false)
2 ответа
Вы, вероятно, должны прочитать это: C++ Boost: Есть ли ошибки с BOOST_FOREACH?
Одна очевидная проблема заключается в том, что ваш марко не расширяется до чего-то такого лексического типа, как это выглядит. В качестве примера рассмотрим
if(condition)
cilk_foreach (auto& value , values) {
//stuff
}
или даже хуже
if(condition)
cilk_foreach (auto& value , values)
// one-line stuff
else
// other stuff
Ответ Хуркила правильный, чтобы избежать этой ошибки, я использую этот макрос:
#define foreach(ARRAY, ITEM) \
for (size_t i = 0, b = 1; b && i != (ARRAY).size(); ++i, b = !b) \
for (auto &ITEM = (ARRAY)[i]; b; b = 0)
Да, у него есть некоторые недостатки, но он демонстрирует реальное поведение цикла for, даже когда он вложен, как в другом ответе. Перерыв и продолжить работу, как ожидалось.
И вы бы использовали это так:
std::vector<int> values(10);
foreach (values, val)
val += 123;