1

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.

Sungmin
  • 2,499
  • 3
  • 26
  • 32

1 Answers1

1

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

user541686
  • 205,094
  • 128
  • 528
  • 886
ForEveR
  • 55,233
  • 2
  • 119
  • 133
  • 2
    That is exceedingly dangerous to use. Just forget to pass in an incremented `v.begin()`, or a decremented `v.end()` and you're in trouble. This also requires a bidirectional range. A better idea would be a `zipped_with` adaptor, and then do `v | zipped_with(next(v), next(v, 2), fun)`. (Hint: Boost.Iterator's `zip_iterator` won't work for this, as it sucks wrt the end condition.) – Xeo Feb 18 '13 at 08:14
  • @Xeo, yes, it's dangerous and not tuned, writed on a knee. – ForEveR Feb 18 '13 at 08:18
  • @ForEveR Sorry for the late reply. I checked your code, and it seems to work. Thanks you. It helps me a lot :) – Sungmin Feb 22 '13 at 03:40