Since C++11 with its range based for
loop, the easiest and simplest is a Range
class template that in addition to supporting the loop, supports set membership checking, e.g. as a method contains
.
One obvious advantage is that with this approach there’s just one simple template, with multiple usages.
And a perhaps not so obvious advantage is that it supports having a const
loop variable, like …
int main()
{
using std::wcout; using std::endl; using cpp::range;
for( auto const i : range( 2, 7 ) )
{
wcout << i << " ";
}
wcout << endl;
if( range( 2, 7 ).contains( 3 ) )
{
wcout << "Yes!" << endl;
}
else
{
wcout << "No!" << endl;
}
}
Definitions like e.g.
#include <utility> // std::begin, std::end
namespace cpp {
template< class Derived >
class Comparable
{
public:
friend bool operator<=( Derived const& a, Derived const& b )
{ return !(b < a); }
friend bool operator>=( Derived const& a, Derived const& b )
{ return !(a < b); }
friend bool operator>( Derived const& a, Derived const& b )
{ return (b < a); }
friend bool operator!=( Derived const& a, Derived const& b )
{ return !(a == b); }
};
template< class TpValue >
class Range
{
public:
typedef TpValue Value;
private:
Value first_;
Value last_;
public:
class Iter
: public Comparable< Iter >
{
private:
Value current_;
public:
Value operator*() const { return current_; }
void operator++() { ++current_; }
friend bool operator<( Iter const a, Iter const b )
{ return a.current_ < b.current_; }
friend bool operator==( Iter const a, Iter const b )
{ return a.current_ == b.current_; }
explicit Iter( Value const v )
: current_( v )
{}
};
Value first() const { return first_; }
Value last() const { return last_; }
Iter begin() const { return Iter( first_ ); }
Iter end() const { return Iter( last_ + 1 ); }
bool contains( Value const x ) const
{ return (first_ <= x && x <= last_); }
Range( Value const first, Value const last )
: first_( first ), last_( last )
{}
};
template< class Value >
Range< Value > range( Value const first, Value const last )
{
return Range< Value >( first, last );
}
template< class Value >
typename Range< Value >::Iter begin( Range< Value > const& r )
{ return r.begin(); }
template< class Value >
typename Range< Value >::Iter end( Range< Value > const& r )
{ return r.end(); }
} // namespace cpp
Generalizing this to deal with floating point ranges is left as an exercise for the reader (it's not asked for here).