安全地重新定义BOOST_FOREACH宏

时间:2012-01-13 23:42:27

标签: c++ boost boost-foreach

我有以下宏:

#define FOREACH(decl, c) BOOST_FOREACH(decl, std::make_pair((c).begin(), (c).end()))

(我正在使用这个宏,因为我的容器没有实现可变迭代API。)

问题在于,c被评估两次。

我的问题是这个宏可以修复,以便:

  1. c最多只评估一次
  2. 为满足第一个条件而创建的任何局部变量仅存在于相应的foreach范围内。

3 个答案:

答案 0 :(得分:8)

您可以使用内联辅助函数。

#define FOREACH(decl, c) BOOST_FOREACH(decl, pair_helper(c))

template <typename T>
inline std::pair<typename T::iterator, typename T::iterator> pair_helper (T c) {
    return std::make_pair(c.begin(), c.end());
}

答案 1 :(得分:6)

没有必要这个hackery。 Boost.Foreach依赖于Boost.Range来检索迭代器。有两种方法可以扩展它:

  1. 提供成员函数和嵌套类型:http://www.boost.org/doc/libs/1_48_0/libs/range/doc/html/range/reference/extending/method_1.html
  2. 提供独立功能并专门化元功能:http://www.boost.org/doc/libs/1_48_0/libs/range/doc/html/range/reference/extending/method_2.html
  3. 现在在您的情况下,看起来您提供了begin()end()成员函数,但是没有提供嵌套类型iterator(我假设你的意思是可变迭代API)。你可以做两件事之一。

    首先,您可以typedef嵌套迭代器类型,如下所示:

    typedef const_iterator iterator;
    

    其次,如果你不能修改类,你可以像这样专门化元函数(用你的容器类型替换你的容器):

    namespace boost
    {
        //
        // Specialize metafunctions. We must include the range.hpp header.
        // We must open the 'boost' namespace.
        //
    
        template< >
        struct range_mutable_iterator< YourContainer >
        {
            typedef YourContainer::const_iterator type;
        };
    
        template< >
        struct range_const_iterator< YourContainer >
        {
            typedef YourContainer::const_iterator type;
        };
    
    } // namespace 'boost'
    

    当然我假设你班上有const_iterator typedef'd(因为你说它不支持可变)。如果不这样做,则需要将YourContainer::const_iterator替换为const_iterator所属的任何类型。

答案 2 :(得分:2)

'Statement-expressions'是gcc/g++ extension,以避免重复评估宏参数

#define make_pair_of_iterators(c) ({typeof(c)& c_ = (c); make_pair(c_.begin(), c_.end()); })

然后你可以这样做:

#define FOREACH(decl, c) BOOST_FOREACH(decl, make_pair_of_iterators(c) )

typeof也是gcc / g ++扩展名。)