2012-01-13 42 views
2

私は次のマクロを持っている:(。私のコンテナが可変反復APIを実装していないので、私は、このマクロを使用しています)再定義BOOST_FOREACHマクロ安全

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

それに伴う問題、ということですcは2回評価されます。

私の質問は、このマクロはように固定することが可能です。

  1. cが第一の条件は、それぞれのforeachの範囲内でのみ生きる満たすために作成されたすべてのローカル変数
  2. 一度ほとんどで評価されます。
+3

このようなマクロハッカーを避け、反復処理を行う場合は、反復文(またはアルゴリズム関数テンプレート)を使用することをお勧めします。 –

+0

@mark、厳密なC++ 03である必要がありますか? g ++固有の拡張機能を許可しますか? –

+0

@Aaron - VS2010を使用しています。したがって、g ++の仕様は範囲外です。 – mark

答えて

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

2番目の 'c'は正直な変数なので、余分なカッコを省略することができます(RIAAエージェントのようなものでない限り)。 –

+0

あなたが正しいです、私はちょうど与えられたマクロからそれを貼り付けコピーします。 –

+0

VS2010では、ペアテンプレートの引数に 'typename'の資格を追加する必要がありましたが、そうでなければうまくいきました。ありがとう。 – mark

2

声明-表現 'をあなたができるマクロ引数の繰り返し評価

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

を避けるためにgcc/g++ extensionです:

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

(そしてtypeofものgcc/gで++拡張機能です)

6

このハッカーは必要ありません。 Boost.Foreachは、イテレータを取得するためにBoost.Rangeに依存しています。どのように拡張する2つの方法があります。

  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の意味を持っていると仮定しています)。あなたは2つのことのうちの1つを行うことができます。

まず、あなたはこのように、ネストされたイテレータ型をtypedefすることができます:あなたは、クラスを変更できない場合

typedef const_iterator iterator; 

第二に、あなたは何でもあなたのコンテナ型でYourContainerを交換する(このように、メタ関数を特化することができます)である:もちろん

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」を持っていると仮定します。そうでない場合は、YourContainer::const_iteratorconst_iteratorのタイプに置き換える必要があります。

関連する問題