Если мы хотим использовать<BOOST_FOREACH>для итерации по новому типу коллекции, мы должны «научить»<BOOST_FOREACH>взаимодействовать с нашим типом. С тех пор<BOOST_FOREACH>Построен на вершинеBoost.Range, мы должны увеличить.Чтобы увеличить<BOOST_FOREACH>. СекцияРасширение. диапазонподробно рассматривает эту тему.
Ниже приведен пример для расширения<BOOST_FOREACH>для итерации по подструнному типу, который содержит два итератора в<std::string>.
namespace my
{
    
    
    struct sub_string
    {
        std::string::iterator begin;
        std::string::iterator end;
        
    };
    
    
    inline std::string::iterator range_begin( sub_string & x )
    {
        return x.begin;
    }
    inline std::string::iterator range_end( sub_string & x )
    {
        return x.end;
    }
    
    
    inline std::string::const_iterator range_begin( sub_string const & x )
    {
        return x.begin;
    }
    inline std::string::const_iterator range_end( sub_string const & x )
    {
        return x.end;
    }
}
namespace boost
{
    
    template<>
    struct range_mutable_iterator< my::sub_string >
    {
        typedef std::string::iterator type;
    };
    template<>
    struct range_const_iterator< my::sub_string >
    {
        typedef std::string::const_iterator type;
    };
}
Теперь, когда мы научилиBoost.Range(и, следовательно,<BOOST_FOREACH>) о нашем типе, мы можем теперь использовать<BOOST_FOREACH>для итерации над нашим подстрочным типом.
my::sub_string substr;
BOOST_FOREACH( char ch, substr )
{
    
}
Есть некоторые проблемы переносимости, о которых мы должны знать при расширении<BOOST_FOREACH>. Обязательно проверьте разделПортативность. В частности, если ваш компилятор не поддерживает Argument-Dependent Lookup,Boost. Диапазон портативностираздел предлагает некоторые предлагаемые обходные пути.
Для типов последовательностей, которые не являются копируемыми, нам нужно будет сказать<BOOST_FOREACH>, чтобы не пытаться делать копии. Если наш тип наследует от<boost::noncopyable>, никаких дальнейших действий не требуется. Если нет, мы должны специализировать шаблон<boost::foreach::is_noncopyable<>>следующим образом:
class noncopy_vector
{
    
private:
    noncopy_vector( noncopy_vector const & ); 
};
namespace boost { namespace foreach
{
    template<>
    struct is_noncopyable< noncopy_vector >
      : mpl::true_
    {
    };
}}
Другой способ добиться такого же эффекта — переопределить глобальную функцию<boost_foreach_is_noncopyable()>. Делая это таким образом, имеет преимущество быть портативным для старых компиляторов.
inline boost::mpl::true_ *
boost_foreach_is_noncopyable( noncopy_vector *&, boost::foreach::tag )
{
    return 0;
}
| ![[Tip]](/img/tip.png) | Tip | 
| Хотя мы должны сказать<BOOST_FOREACH>, что наш тип не является копируемым, это не означает, что<BOOST_FOREACH>всегда делает копию нашего типа последовательности. Очевидно, что это будет дорого и даже неправильно в некоторых случаях.<BOOST_FOREACH>довольно умно о том, когда делать копию, а когда нет.<is_noncopyable<>>черта необходима, чтобы удалить копию, которая находится на ветке, которая может никогда не быть взята. | 
На некоторых компиляторах<BOOST_FOREACH>иногда требуется несколько более медленный путь кода, чтобы гарантировать правильную обработку последовательностей, хранящихся во временных объектах. Он спрашивает себя: «Должен ли я сделать копию этого объекта?», а затем: «Я сделал копию или нет?» Для некоторых типов последовательностей это перебор. Рассмотрим последовательность, которая представляет собой простую пару итераторов. Прыгать через обручи огня, чтобы избежать копирования, не имеет смысла, потому что копирование очень дешево.
Пара итераторов является примером легкого прокси. Он не хранит значения последовательности; скорее, он хранит итераторы для них. Это означает, что повторение над копией прокси-объекта даст те же результаты, что и использование самого объекта. Для таких типов<BOOST_FOREACH>обеспечивает крючок, который позволяет нам сказать ему, чтобы он не беспокоился о расходах на изготовление копии. Это может привести к немного более быстрому выполнению цикла. Просто специализируйте черту<boost::foreach::is_lightweight_proxy<>>следующим образом:
struct sub_string
  : boost::iterator_range< std::string::iterator >
{
    
};
namespace boost { namespace foreach
{
    template<>
    struct is_lightweight_proxy< sub_string >
      : mpl::true_
    {
    };
}}
С другой стороны, мы могли бы достичь того же эффекта, переопределив глобальную функцию<boost_foreach_is_lightweight_proxy()>следующим образом:
inline boost::mpl::true_ *
boost_foreach_is_lightweight_proxy( sub_string *&, boost::foreach::tag )
{
    return 0;
}
Этот метод переносим на более старые компиляторы.