
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; }