2012-01-13 2 views
2

У меня есть следующий макрос:Redefine BOOST_FOREACH макрос безопасно

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

(. Я использую этот макрос, потому что мои контейнеры не реализуют изменяемые итерации API)

Проблему с этим, что c оценивают дважды.

Мой вопрос может этот макрос быть закреплены так, чтобы:

  1. c оценивается в самый раз
  2. Любые локальные переменные, созданные для того, чтобы удовлетворить первое условие жить в пределах соответствующего Еогеасп только сферы.
+3

Лучше избегать такого рода хакерских атак и использовать итерационные утверждения (или шаблоны функций алгоритма), когда вы хотите итерации. –

+0

@mark, Должен ли он быть строгим C++ 03. Например, допустим ли вы g ++ конкретные расширения? –

+0

@ Аарон - я использую 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

Поскольку вторая 'c' является честной переменной, вы можете опустить эти дополнительные скобки (если только вы не являетесь агентом RIAA). –

+0

Вы правы, я просто скопировал его из заданного макроса. Исправлено: –

+0

На VS2010 мне пришлось добавлять атрибуты 'typename' к аргументам пары шаблонов, но в остальном он работал нормально. Благодарю. – mark

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 также .)

6

Не нужно использовать этот хакер. 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; 

Во-вторых, если вы не можете изменить класс, вы можете специализировать метафункции, как это (замена 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_iterator любым типом вашего const_iterator.

Смежные вопросы