Search code examples
c++boostc++11boost-range

boost range adaptor similar to transformed which can access adjacent elements


I want to make a range which transformed by adjacent values of given range. Is there a way to achieve this? Thus, I want to make an adjacent_transformed which described in the code below.

class Func{
public:
    typedef int result_type;

    int operator()(int a, int b, int c) {
        return a+b+c;        
    }

};

int main(){
    vector<int> v{1,1,1,1,1};
    auto rng = make_iterator_range( next(v.begin(), prev(v.end()) ) | adjacent_transformed( Func() );
    // rng shoud be {3, 3, 3}
}

Another quick question : Is it safe to pass rvalue which is Func() into the range adapter boost::adaptors::transformed?? As far as I tested, it works as expected. If it is safe, is Func() copied into the transformed? Then, what should I do if Func() is costly to copy?

Sorry if it is not a relevant question, but I am not skilled enough to understand the internals of boost range.


Solution

  • You can use something like this. I think it should be tuned, but it works.

    template<typename Iterator, typename Functor>
    class iterator : public boost::iterator_adaptor<
                     iterator<Iterator, Functor>,
                     Iterator,
                     typename std::iterator_traits<Iterator>::value_type,
                     boost::forward_traversal_tag,
                     typename std::iterator_traits<Iterator>::value_type,
                     typename std::iterator_traits<Iterator>::difference_type
                >, private Functor
    {
       typedef boost::iterator_adaptor<
                     iterator<Iterator, Functor>,
                     Iterator,
                     typename std::iterator_traits<Iterator>::value_type,
                     boost::forward_traversal_tag,
                     typename std::iterator_traits<Iterator>::value_type,
                     typename std::iterator_traits<Iterator>::difference_type
                > base_t;
    public:
       friend class boost::iterator_core_access;
    
       iterator(Iterator current, Functor fnc):
          base_t(current),
          Functor(fnc)
       {
       }
    
       typename std::iterator_traits<Iterator>::value_type dereference() const
       {
          Iterator i = this->base();
          const Functor& fnc = *this;
          return fnc(*boost::prior(i), *i, *boost::next(i));
       }
    };
    
    template<typename Iter, typename Func>
    iterator<Iter, Func> make_iterator(Iter i, Func f)
    {
       return iterator<Iter, Func>(i, f);
    }
    
    template<typename F, typename R>
    struct trans_range : public boost::iterator_range<
                         iterator<typename boost::range_iterator<R>::type,
                         F>>
    {
       typedef boost::iterator_range<
                         iterator<typename boost::range_iterator<R>::type,
                         F>> base_t;
       trans_range(F f, R& r) :
          base_t(make_iterator(boost::begin(r), f), make_iterator(boost::end(r), f))
       {
       }
    };
    
    template< class T >
    struct holder
    {
       T val;
       holder( T t ) : val(t)
       { }
    };
    
    template<typename T>
    struct trans_holder : holder<T>
    {
       trans_holder(T r) : holder<T>(r) { }
    };
    
    template< template<class> class Holder >
    struct forwarder
    {
       template< class T >
       Holder<T> operator()( T t ) const
       {
           return Holder<T>(t);
       }
    };
    
    template<typename R, typename F>
    inline trans_range<F, R> operator |(R range, const trans_holder<F>& f)
    {
       return trans_range<F, R>(f.val, range);
    }
    
    forwarder<trans_holder> transformed = forwarder<trans_holder>();
    

    example