Iterators and circulators as well as different categories of circulators can be distinguished with the use of discriminating functions and the following circulator tags. A couple of base classes simplify the task of writing own circulators. They declare the appropriate tags and the local types needed for circulators. To use the tags or base classes only it is sufficient to include:
#include <CGAL/circulator_bases.h>
#include <CGAL/circulator.h>
| |
|
query_circulator_or_iterator,
Circulator_traits,
Assert_circulator,
CGAL_For_all,
is_empty_range,
Circulator.
The above declarations can be used to distinguish between iterators and circulators and between different circulator categories. The assertions can be used to protect a templatized algorithm against instantiations that do not fulfill the requirements. The following example program illustrates both.
File: examples/Circulator/circulator_prog3.cpp
#include <CGAL/basic.h> #include <cassert> #include <list> #include <CGAL/circulator.h> template <class C> inline int foo( C c, std::forward_iterator_tag) { CGAL::Assert_circulator( c); CGAL::Assert_forward_category( c); return 1; } template <class C> inline int foo( C c, std::random_access_iterator_tag) { CGAL::Assert_circulator( c); CGAL::Assert_random_access_category( c); return 2; } template <class I> inline int foo( I i, CGAL::Iterator_tag) { CGAL::Assert_iterator( i); return 3; } template <class C> inline int foo( C c, CGAL::Circulator_tag) { CGAL::Assert_circulator( c); typedef std::iterator_traits<C> Traits; typedef typename Traits::iterator_category iterator_category; return foo( c, iterator_category()); } template <class IC> inline int foo( IC ic) { typedef CGAL::Circulator_traits<IC> Traits; typedef typename Traits::category category; return foo( ic, category()); } int main() { typedef CGAL::Forward_circulator_base<int> F; typedef CGAL::Random_access_circulator_base<int> R; F f = F(); R r = R(); std::list<int> l; assert( foo( f) == 1); assert( foo( r) == 2); assert( foo( l.begin()) == 3); return 0; }
Since not all current compilers can eliminate the space needed for the compile time tags even when deriving from them, we implement a variant for each base class that contains a protected void* data member called _ptr. Here, the allocated space in the derived classes can be reused.