Boost logo

Boost Users :

From: David Hall (dlwh_at_[hidden])
Date: 2005-09-23 17:08:35


Simon Buchan wrote:

> Played around a bit, try this. It only defines is_in (which wraps
> 'std::find(rhs.begin(), rhs.end(), lhs) != rhs.end()' ),
> but should be easily generalisable to any operation, say:
> if(x <is_in> vec) {while(int i <for_all_in> vec) cout << i;}
> (I don't know if you could do the last one, or what syntax would be
> better suited, but you get the idea)

Anything like "while(int i <for_all_in> vec) cout << i;" isn't all that
feasible (without being really hackish), since you need to maintain some
sort of state inside of something that lives beyond each while
statement, but specifically not in for_all_in, since we want to be able
to iterate over the same container twice.

The best I can come up with is this: (This could be prettified if we
had auto, with the added bonus of allowing for autoselection of const
versus non-const iterators.)
    for_all_in_iterator<std::vector<int> > i;
    while( i <for_all_in> vec)
        std::cout << *i << std::endl;

where for_all_in_iterator is essentially a specialized form of
boost::optional<>. I don't think you can get around using an iterator,
unless you're willing to sacrifice either for_all_in's reentry or status
as pseudo-keyword.

Either way, I added my code in, with a few edits to yours, to allow for
non-const RhsT. Ideally, there'd be a for_all_in_const_iterator version,
but that's pretty easy.

David Hall


#include <vector>
#include <algorithm>
#include <iostream>
#include <cassert>

namespace boost { namespace infix {
namespace detail {
        template <typename LhsT, typename Operator>
        struct binder
        {
                explicit binder(LhsT& _lhs)
                : lhs(_lhs)
                {}

                template <typename RhsT>
                typename Operator::template sig<LhsT, RhsT>::type
                operator > (RhsT& rhs)
                { return Operator::apply(lhs, rhs);
                }
                
                template <typename RhsT>
                typename Operator::template sig<LhsT, RhsT>::type
                operator > (const RhsT& rhs)
                { return Operator::apply(lhs, rhs);
                }

                // SFINAE version of the above using ::result_type

                // ...
        private:
                LhsT& lhs;
        };

        // lots of other things
}

struct is_in_operator
{ template <typename ValueT, typename Cont>
        static bool
        apply(const ValueT& val, const Cont& cont)
        { return std::find
                ( cont.begin()
                , cont.end()
                , val
                ) != cont.end();
        }

        template <typename LhsT, typename RhsT>
        struct sig
        { typedef bool type;
        };
} is_in;

// Ugly version of the adapter pattern, perhaps too similar to boost::optional
// A state of valid implies that for_all_in has been applied to this iterator at least once.
template <class Cont>
class for_all_in_iterator
{
typedef typename Cont::iterator real_iter_t;
typedef typename Cont::value_type value_type;
public:
        for_all_in_iterator():valid(false)
        {}
        
        for_all_in_iterator(const for_all_in_iterator & rhs)
        : valid(rhs.valid), iter(rhs.iter)
        {}
 
        for_all_in_iterator(const real_iter_t & rhs)
        : valid(false), iter(rhs)
        {}
        
 
        for_all_in_iterator & operator=(const real_iter_t & rhs)
        {
                iter = rhs;
                return *this;
        }
 
        real_iter_t & operator->()
        {
                return iter;
        }
 
        const real_iter_t & operator->() const
        {
                return iter;
        }
 
        value_type & operator*()
        {
                return *iter;
        }
 
        const value_type & operator*() const
        {
                return *iter;
        }

        for_all_in_iterator & operator++()
        {
                ++iter;
                return *this;
        }
        
        for_all_in_iterator operator++(int)
        {
                for_all_in_iterator tmp(*this);
                operator++();
                return tmp;
        }
        
        bool operator==(const for_all_in_iterator & rhs) const
        {
                return iter == rhs.iter;
        }
        
        bool operator!=(const for_all_in_iterator & rhs) const
        {
                return iter != rhs.iter;
        }
        
        bool operator<(const for_all_in_iterator & rhs) const
        {
                return iter < rhs.iter;
        }
        
        bool operator>(const for_all_in_iterator & rhs) const
        {
                return iter > rhs.iter;
        }
        
        bool operator<=(const for_all_in_iterator & rhs) const
        {
                return iter <= rhs.iter;
        }
        
        bool operator>=(const for_all_in_iterator & rhs) const
        {
                return iter >= rhs.iter;
        }
        
        // Let's not be picky here.
        template <class OtherIter>
        bool operator==(const OtherIter & rhs) const
        {
                return iter == rhs;
        }
        
        template <class OtherIter>
        bool operator!=(const OtherIter & rhs) const
        {
                return iter != rhs;
        }
        
        template <class OtherIter>
        bool operator<(const OtherIter & rhs) const
        {
                return iter < rhs;
        }
        
        template <class OtherIter>
        bool operator>(const OtherIter & rhs) const
        {
                return iter > rhs;
        }
        
        template <class OtherIter>
        bool operator<=(const OtherIter & rhs) const
        {
                return iter <= rhs;
        }
        
        template <class OtherIter>
        bool operator>=(const OtherIter & rhs) const
        {
                return iter >= rhs;
        }
        
private:
        bool valid;
        real_iter_t iter;
        friend class for_all_in_operator;
};

struct for_all_in_operator
{ template <typename Cont>
        static bool
        apply (for_all_in_iterator<Cont> & iter, Cont& cont)
        {
                if(!iter.valid)
                {
                        iter.iter = cont.begin();
                        iter.valid = true;
                        return true;
                }
                
                if(iter.iter == cont.end())
                        return false;
                        
                return ++iter != cont.end();
        }
        
        template <typename LhsT, typename RhsT>
        struct sig
        { typedef bool type;
        };
} for_all_in;

// Lots of other infix operators

template <typename LhsT, typename Operator>
detail::binder<LhsT, Operator>
operator < (LhsT& lhs, Operator rhs)
{ return detail::binder<LhsT, Operator>(lhs);
}

}}

int main()
{ using namespace boost::infix;
        std::vector<int> vec;
        int val = 6;
        vec.push_back(4);
        vec.push_back(7);
        vec.push_back(6);
  assert(val <is_in> vec);
  // The following could be a lot prettier with auto, oh well.
        for_all_in_iterator<std::vector<int> > i;
        while( i <for_all_in> vec)
                std::cout << *i << std::endl;
}


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net