|
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