Question

In Intel Cilk Plus extension there's this keyword cilk_for (or _Cilk_for actually). It's like the keyword for, but more restrictive and its iterations run in parallel. I wrote a convenience macro in the spirit of BOOST_FOREACH, which uses cilk_for internally. Can you see any problems with the following implementation?

#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)

You would use it like so:

std::vector<int> values (10);

cilk_foreach (auto& value , values)
{
    value += 123;
}

EDIT

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)
Was it helpful?

Solution

You should probably read this: C++ Boost: Any gotchas with BOOST_FOREACH?

One obvious problem is that your marco doesn't expand into something that has the lexical type it looks like it has. As an example, consider

if(condition)
    cilk_foreach (auto& value , values) {
        //stuff
    }

or even worse

if(condition)
    cilk_foreach (auto& value , values) 
        // one-line stuff
else
    // other stuff

OTHER TIPS

The answer by Hurkyl is correct, to prevent this error I use this macro:

#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)

Yes, it's got some downsides, but does expose the real for-loop behavior even when nested like in the other answer. Break and continue work as expected.

And you would use it like this:

std::vector<int> values(10);
foreach (values, val)
    val += 123;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top