2012-01-13 63 views
2

我有以下宏:重新定義BOOST_FOREACH宏安全

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

(我使用這個宏,因爲我的容器不執行可變迭代API)

的問題吧,是c被評估兩次。

我的問題是可以在這個宏固定的,因此:

  1. c最多一次
  2. 爲了滿足第一個條件只生活在各自的foreach範圍內創建的任何局部變量進行評估。
+3

最好避免這種類型的宏hackery,並在迭代時使用迭代語句(或算法函數模板)。 – 2012-01-13 23:45:09

+0

@mark,它是否必須嚴格C++ 03。例如,你會允許g ++特定的擴展嗎? – 2012-01-13 23:56:41

+0

@Aaron - 我使用VS2010。所以g ++細節不在範圍之內。 – mark 2012-01-14 09:46:14

回答

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

既然第二個'c'是一個誠實的變量,你可以省略那些額外的括號(除非你是某種RIAA代理)。 – 2012-01-14 00:20:50

+0

你說得對,我只是從給定的宏複製粘貼它。固定 – 2012-01-14 00:29:12

+0

在VS2010上,我不得不將'typename'限定添加到配對模板參數中,但是否則它工作得很好。謝謝。 – mark 2012-01-14 19:50:12

2

'語句表達式' 是一個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 ++的擴展也)

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

現在,在你的情況下,它看起來像你提供的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_iteratortypedef「d(既然你說,它不支持可變)。如果你不這樣做,你將需要用const_iterator的任何類型替換YourContainer::const_iterator