这个foreach宏实现是否有任何问题

时间:2012-08-12 08:16:33

标签: c++ c++11 macros foreach cilk-plus

在英特尔Cilk Plus扩展中,有一个关键字cilk_for(或实际上是_Cilk_for)。它就像关键字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 个答案:

答案 0 :(得分:3)

你应该读这个:C++ Boost: Any gotchas with BOOST_FOREACH?

一个明显的问题是你的marco没有扩展到具有它看起来像它的词汇类型的东西。例如,考虑

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

甚至更糟

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

答案 1 :(得分:2)

Hurkyl的答案是正确的,为了防止这个错误我使用这个宏:

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