iterator_categories reformed, test added

[SVN r20829]
This commit is contained in:
Dave Abrahams
2003-11-17 16:52:15 +00:00
parent 6ec791e3b9
commit 6f90b8b161
2 changed files with 171 additions and 721 deletions

View File

@ -1,335 +1 @@
// (C) Copyright Thomas Witt 2002. Permission to copy, use, modify,
// sell and distribute this software is granted provided this
// copyright notice appears in all copies. This software is provided
// "as is" without express or implied warranty, and with no claim as
// to its suitability for any purpose.
#ifndef BOOST_ITERATOR_DETAIL_CATEGORIES_HPP
# define BOOST_ITERATOR_DETAIL_CATEGORIES_HPP
# include <boost/config.hpp>
# include <boost/iterator/detail/config_def.hpp>
# include <boost/detail/workaround.hpp>
# include <boost/type_traits/is_convertible.hpp>
# include <boost/type_traits/is_same.hpp>
# include <boost/mpl/if.hpp>
# include <boost/mpl/apply_if.hpp>
# include <boost/mpl/identity.hpp>
# include <boost/mpl/bool.hpp>
# include <boost/mpl/or.hpp>
# include <boost/mpl/and.hpp>
# include <boost/mpl/integral_c.hpp>
# include <boost/mpl/aux_/lambda_support.hpp>
# include <iterator>
namespace boost
{
// faked new old-style categories needed to make new->old mapping
// work
namespace detail
{
struct null_category_tag {};
struct input_output_iterator_tag : std::input_iterator_tag, std::output_iterator_tag {};
}
//
// Access Categories
//
enum iterator_access
{
readable_iterator = 1
, writable_iterator = 2
, swappable_iterator = 4
, lvalue_iterator = 8
};
//
// Traversal Categories
//
struct incrementable_traversal_tag
{
typedef std::output_iterator_tag max_category;
};
struct single_pass_traversal_tag
: incrementable_traversal_tag
{
typedef detail::input_output_iterator_tag max_category;
};
struct forward_traversal_tag
: single_pass_traversal_tag
{
typedef std::forward_iterator_tag max_category;
};
struct bidirectional_traversal_tag
: forward_traversal_tag
{
typedef std::bidirectional_iterator_tag max_category;
};
struct random_access_traversal_tag
: bidirectional_traversal_tag
{
typedef std::random_access_iterator_tag max_category;
};
struct error_iterator_tag { };
namespace detail
{
template <unsigned access>
struct access_c : mpl::integral_c<iterator_access,(iterator_access)access>
{};
//
// Tag detection meta functions
//
// I bet this is defined somewhere else. Let's wait and see.
struct error_type;
# ifndef BOOST_NO_IS_CONVERTIBLE
// True iff T is a tag "derived" from Tag
template <class Tag, class T>
struct is_tag
: mpl::or_<
is_convertible<T, Tag>
// Because we can't actually get forward_iterator_tag to
// derive from input_output_iterator_tag, we need this
// case.
, mpl::and_<
is_convertible<T,std::forward_iterator_tag>
, is_convertible<detail::input_output_iterator_tag,Tag>
>
>
{};
# else
template <class Tag, class T>
struct is_tag;
# endif
// Generate specializations which will allow us to find
// null_category_tag as a minimum old-style category for new-style
// iterators which don't have an actual old-style category. We
// need that so there is a valid base class for all new-style
// iterators.
# define BOOST_OLD_ITERATOR_CATEGORY(category) \
template <> \
struct is_tag <detail::null_category_tag, std::category> \
: mpl::true_ {};
BOOST_OLD_ITERATOR_CATEGORY(input_iterator_tag)
BOOST_OLD_ITERATOR_CATEGORY(output_iterator_tag)
BOOST_OLD_ITERATOR_CATEGORY(forward_iterator_tag)
BOOST_OLD_ITERATOR_CATEGORY(bidirectional_iterator_tag)
BOOST_OLD_ITERATOR_CATEGORY(random_access_iterator_tag)
# undef BOOST_OLD_ITERATOR_CATEGORY
template <>
struct is_tag<detail::input_output_iterator_tag,std::forward_iterator_tag>
: mpl::true_
{
};
# ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
template <class T>
struct is_tag<T,T> : mpl::true_
{};
# ifdef BOOST_NO_IS_CONVERTIBLE
// Workarounds for CWPro7 which can't detect derivation at
// compile-time.
// Fact of life: we can only detect tag refinement relationships
// among predefined tags.
//
// Algorithm:
// is_tag(T,U) ->
// T == U
// || (exists d in derived_from(T) such that is_tag(d, U))
//
// T == U case is handled above
// false by default
template <class Tag, class T>
struct is_tag_impl : mpl::false_
{};
// The generalized template dispatches to is_tag_impl because
// is_tag<T,T> and is_tag<some_tag,T> are equally specialized.
// This technique simulates making is_tag<T,T> more-specialized.
template <class Tag, class T>
struct is_tag
: is_tag_impl<Tag, T>
{};
# define BOOST_ITERATOR_DERIVED_TAG1(base, derived) \
BOOST_ITERATOR_DERIVED_TAG1_AUX(base, _, derived)
# define BOOST_ITERATOR_DERIVED_TAG1_AUX(base, underscore, derived) \
template<class T> \
struct is_tag_impl<base##underscore##tag, T> \
: is_tag<derived##underscore##tag, T> \
{ \
};
// Old-style tag relations
template<class T>
struct is_tag_impl<detail::null_category_tag, T>
: mpl::or_<
is_tag<std::output_iterator_tag, T>
, is_tag<std::input_iterator_tag, T>
>
{
};
BOOST_ITERATOR_DERIVED_TAG1(std::output_iterator, detail::input_output_iterator)
BOOST_ITERATOR_DERIVED_TAG1(std::input_iterator, detail::input_output_iterator)
BOOST_ITERATOR_DERIVED_TAG1(detail::input_output_iterator, std::forward_iterator)
BOOST_ITERATOR_DERIVED_TAG1(std::forward_iterator, std::bidirectional_iterator)
BOOST_ITERATOR_DERIVED_TAG1(std::bidirectional_iterator, std::random_access_iterator)
// Access tag relations
BOOST_ITERATOR_DERIVED_TAG1(readable_lvalue_iterator, writable_lvalue_iterator)
BOOST_ITERATOR_DERIVED_TAG1(swappable_iterator, readable_writable_iterator)
BOOST_ITERATOR_DERIVED_TAG1(readable_writable_iterator, writable_lvalue_iterator)
template<class T>
struct is_tag_impl<readable_iterator_tag, T>
: mpl::or_<
is_tag<readable_lvalue_iterator_tag, T>
, is_tag<readable_writable_iterator_tag, T>
>
{
};
BOOST_ITERATOR_DERIVED_TAG1(writable_iterator, readable_writable_iterator)
// Traversal tag relations
BOOST_ITERATOR_DERIVED_TAG1(bidirectional_traversal, random_access_traversal)
BOOST_ITERATOR_DERIVED_TAG1(forward_traversal, bidirectional_traversal)
BOOST_ITERATOR_DERIVED_TAG1(single_pass_traversal, forward_traversal)
BOOST_ITERATOR_DERIVED_TAG1(incrementable_traversal, single_pass_traversal)
# endif // BOOST_NO_IS_CONVERTIBLE workarounds
# endif // ndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
// If TraversalTag is convertible to Known, return it, otherwise
// return the result of invoking NullaryElse
template <class TraversalTag, class Known, class NullaryElse>
struct known_traversal_tag
: mpl::apply_if<
is_convertible<TraversalTag,Known>
, mpl::identity<Known>
, NullaryElse
>
{};
template <class Tag>
struct max_known_traversal_tag
: known_traversal_tag<
Tag, random_access_traversal_tag
, known_traversal_tag<
Tag, bidirectional_traversal_tag
, known_traversal_tag<
Tag, forward_traversal_tag
, known_traversal_tag<
Tag, single_pass_traversal_tag
, known_traversal_tag<
Tag, incrementable_traversal_tag
, error_iterator_tag
>
>
>
>
>
{};
template <class AccessTag, unsigned Known, class NullaryElse>
struct known_access_tag
: mpl::apply_if_c<
((AccessTag::value & Known) == Known)
, mpl::identity<access_c<Known> >
, NullaryElse
>
{};
// Doesn't cope with these odd combinations: readable+swappable,
// writable+swappable. That doesn't matter for the sake of
// new-style tag base computation, which is all it's used for
// anyway.
template <class Tag>
struct max_known_access_tag
: known_access_tag<
Tag, (writable_iterator|readable_iterator|swappable_iterator|lvalue_iterator)
, known_access_tag<
Tag, (readable_iterator|lvalue_iterator)
, known_access_tag<
Tag, (writable_iterator|readable_iterator|swappable_iterator)
, known_access_tag<
Tag, writable_iterator
, known_access_tag<
Tag, readable_iterator
, mpl::apply_if_c<
(swappable_iterator & Tag::value)
, mpl::identity<null_category_tag>
, error_iterator_tag
>
>
>
>
>
>
{};
//
// Returns the minimum category type or error_type
// if T1 and T2 are unrelated.
//
// For compilers not supporting is_convertible this only
// works with the new boost return and traversal category
// types. The exact boost _types_ are required. No derived types
// will work.
//
//
template <class T1, class T2>
struct minimum_category
: mpl::apply_if<
is_tag<T1,T2>
, mpl::identity<T1>
, mpl::if_<
is_tag<T2, T1>
, T2
, error_type
>
>
{
BOOST_MPL_AUX_LAMBDA_SUPPORT(2,minimum_category,(T1,T2))
};
# if BOOST_WORKAROUND(BOOST_MSVC, <= 1200)
// Deal with ETI
template <> struct minimum_category<int, int> { typedef minimum_category type; };
# endif
} // namespace detail
} // namespace boost
#include <boost/iterator/detail/config_undef.hpp>
#endif // BOOST_ITERATOR_DETAIL_CATEGORIES_HPP
#error obsolete

View File

@ -4,411 +4,195 @@
// "as is" without express or implied warranty, and with no claim as
// to its suitability for any purpose.
// TODO:
// Add separate category tag for operator[].
#ifndef BOOST_ITERATOR_CATEGORIES_HPP
#define BOOST_ITERATOR_CATEGORIES_HPP
# define BOOST_ITERATOR_CATEGORIES_HPP
#include <boost/config.hpp>
#include <boost/iterator/detail/categories.hpp>
# include <boost/config.hpp>
# include <boost/detail/iterator.hpp>
# include <boost/iterator/detail/config_def.hpp>
#include <boost/type_traits/conversion_traits.hpp>
#include <boost/type_traits/cv_traits.hpp>
# include <boost/detail/workaround.hpp>
#include <boost/python/detail/indirect_traits.hpp>
#include <boost/detail/iterator.hpp>
#include <boost/detail/workaround.hpp>
#include <boost/mpl/apply_if.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/mpl/aux_/has_xxx.hpp>
#include <boost/mpl/not.hpp>
#include <boost/mpl/or.hpp>
#include <boost/mpl/apply.hpp>
#include <boost/mpl/aux_/msvc_eti_base.hpp>
#ifdef BOOST_MPL_NO_FULL_LAMBDA_SUPPORT
# include <boost/mpl/if.hpp>
# include <boost/mpl/and.hpp>
# include <boost/mpl/apply_if.hpp>
# include <boost/mpl/identity.hpp>
# include <boost/mpl/placeholders.hpp>
#endif
# include <boost/mpl/aux_/lambda_support.hpp>
#include <iterator>
#include <boost/iterator/detail/config_def.hpp> // must be last #include
#if BOOST_WORKAROUND(__MWERKS__, <=0x2407)
# define BOOST_NO_IS_CONVERTIBLE // "Convertible does not provide enough/is not working"
#endif
# include <boost/type_traits/is_reference.hpp>
# include <boost/type_traits/is_convertible.hpp>
# include <boost/type_traits/is_const.hpp>
namespace boost {
namespace detail
//
// Traversal Categories
//
struct incrementable_traversal_tag {};
struct single_pass_traversal_tag
: incrementable_traversal_tag {};
struct forward_traversal_tag
: single_pass_traversal_tag {};
struct bidirectional_traversal_tag
: forward_traversal_tag {};
struct random_access_traversal_tag
: bidirectional_traversal_tag {};
namespace detail
{
struct input_output_iterator_tag
: std::input_iterator_tag, std::output_iterator_tag {};
template <class Value, class Reference, class Traversal>
struct old_iterator_category
{
// Helper metafunction for std_category below
template <class Cat, class Tag, class Next>
struct match_tag
: mpl::apply_if<is_tag<Tag, Cat>, mpl::identity<Tag>, Next>
{
};
// Converts a possibly user-defined category tag to the
// most-derived standard tag which is a base of that tag.
template <class Category>
struct std_category
: match_tag<
Category, std::random_access_iterator_tag
, match_tag<Category, std::bidirectional_iterator_tag
, match_tag<Category, std::forward_iterator_tag
, match_tag<Category, std::input_iterator_tag
, match_tag<Category, std::output_iterator_tag
# if BOOST_WORKAROUND(BOOST_MSVC, <= 1300)
, mpl::identity<void>
# else
, void
# endif
>
>
>
>
>
{
};
// std_to_new_tags --
//
// A metafunction which converts any standard tag into its
// corresponding new-style traversal tag.
//
// Also, instantiations are metafunction classes which convert a
// reference type into a corresponding new-style access tag.
template <class Category> struct std_to_new_tags
# if BOOST_WORKAROUND(BOOST_MSVC, == 1300) // handle ETI
{
typedef void type;
template <class T> struct apply { typedef void type; };
}
# endif
;
# if BOOST_WORKAROUND(BOOST_MSVC, <= 1200) // handle ETI
template <> struct std_to_new_tags<int> {};
# endif
//
// Specializations for specific standard tags
//
template <>
struct std_to_new_tags<std::input_iterator_tag>
{
typedef single_pass_traversal_tag type;
template <class Reference>
struct apply
: access_c<readable_iterator> {};
};
template <>
struct std_to_new_tags<std::output_iterator_tag>
{
typedef incrementable_traversal_tag type;
template <class Reference>
struct apply
: access_c<writable_iterator> {};
};
template <>
struct std_to_new_tags<std::forward_iterator_tag>
{
typedef forward_traversal_tag type;
template <class Reference>
struct apply
: mpl::if_<
python::detail::is_reference_to_const<Reference>
, access_c<(readable_iterator|lvalue_iterator)>
, access_c<(readable_iterator|writable_iterator|lvalue_iterator)>
>
{};
};
template <>
struct std_to_new_tags<std::bidirectional_iterator_tag>
: std_to_new_tags<std::forward_iterator_tag>
{
typedef bidirectional_traversal_tag type;
};
template <>
struct std_to_new_tags<std::random_access_iterator_tag>
: std_to_new_tags<std::bidirectional_iterator_tag>
{
typedef random_access_traversal_tag type;
};
template <class Category>
struct old_tag_converter
: std_to_new_tags<
// Take the category down to its most-refined known
// std::tag, in case of derivation/convertibility
typename std_category<Category>::type
>
{
};
template <class OldTag>
struct old_tag_to_traversal
: old_tag_converter<OldTag>
{};
template <typename Category, typename Reference>
struct old_tag_to_access
: mpl::apply1<
old_tag_converter<Category>
, Reference
>
{};
# if BOOST_WORKAROUND(BOOST_MSVC, <= 1200)
// Deal with ETI
template <> struct old_tag_to_access<int, int> {};
template <> struct old_tag_converter<int> {};
# endif
// A metafunction returning true iff T is boost::iterator_tag<R,U>
template <class T>
struct is_boost_iterator_tag;
#if BOOST_WORKAROUND(__MWERKS__, <= 0x2407)
//
// has_xxx fails, so we have to use
// something less sophisticated.
//
// The solution depends on the fact that only
// std iterator categories work with is_xxx_iterator
// meta functions, as BOOST_NO_IS_CONVERTIBLE is
// defined for cwpro7.
//
template <class Tag>
struct is_new_iterator_tag
: mpl::not_<
mpl::or_<
is_tag<std::input_iterator_tag, Tag>
, is_tag<std::output_iterator_tag, Tag>
>
>
{};
#elif BOOST_WORKAROUND(__GNUC__, == 2 && __GNUC_MINOR__ == 95) \
|| BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x551))
template <class Tag>
struct is_new_iterator_tag
: is_boost_iterator_tag<Tag>
{
};
#else
BOOST_MPL_HAS_XXX_TRAIT_DEF(traversal)
template <class Tag>
struct is_new_iterator_tag
: mpl::if_<
is_class<Tag>
, has_traversal<Tag>
, mpl::false_
>::type
{
};
#endif
} // namespace detail
namespace detail {
template <class NewCategoryTag>
struct new_tag_to_traversal
{
typedef typename NewCategoryTag::traversal type;
};
template <class NewCategoryTag>
struct new_tag_to_access
{
typedef typename NewCategoryTag::access_type type;
};
#if 0 // what was this all about?
template <class NewCategoryTag, class Reference>
struct new_tag_to_access
: mpl::apply_if<
python::detail::is_reference_to_const<Reference>
, remove_access_writability<typename NewCategoryTag::access>
, mpl::identity<typename NewCategoryTag::access>
>
{};
#endif
template <class CategoryTag, class Reference>
struct tag_access_category
: mpl::apply_if<
is_new_iterator_tag<CategoryTag>
, new_tag_to_access<CategoryTag>
, old_tag_to_access<CategoryTag, Reference>
>
{
};
template <class CategoryTag>
struct tag_traversal_category
: mpl::apply_if<
is_new_iterator_tag<CategoryTag>
, new_tag_to_traversal<CategoryTag>
, old_tag_to_traversal<CategoryTag>
>
{
};
# if BOOST_WORKAROUND(BOOST_MSVC, <= 1200)
// Deal with ETI
template <> struct tag_access_category<int, int> { typedef void type; };
template <> struct tag_traversal_category<int> { typedef void type; };
# endif
// iterator_tag_base - a metafunction to compute the appropriate
// old-style tag (if any) to use as a base for a new-style tag.
template <class KnownAccessTag, class KnownTraversalTag>
struct iterator_tag_base
: minimum_category<
typename KnownAccessTag::max_category
, typename KnownTraversalTag::max_category
>
{};
# if BOOST_WORKAROUND(BOOST_MSVC,<=1200)
template <>
struct iterator_tag_base<int,int>
: mpl::false_ {}; // just using false_ so that the result will be
// a legal base class
typedef typename mpl::
# if BOOST_WORKAROUND(BOOST_MSVC, == 1200)
if_
# else
apply_if
# endif
<
mpl::and_<
is_reference<Reference>
, is_convertible<Traversal,forward_traversal_tag>
>
, mpl::apply_if<
is_convertible<Traversal,random_access_traversal_tag>
, mpl::identity<std::random_access_iterator_tag>
, mpl::if_<
is_convertible<Traversal,bidirectional_traversal_tag>
, std::bidirectional_iterator_tag
, std::forward_iterator_tag
>
>
# if BOOST_WORKAROUND(BOOST_MSVC, == 1200)
::type
# endif
, typename mpl::apply_if<
mpl::and_<
is_convertible<Traversal, single_pass_traversal_tag>
, is_convertible<Reference, Value>
>
, mpl::if_<
is_const<Value>
, std::input_iterator_tag
, input_output_iterator_tag
>
, mpl::identity<std::output_iterator_tag>
>
# if BOOST_WORKAROUND(BOOST_MSVC, == 1200)
::type
# endif
>::type type;
};
// specialization for this special case. Otherwise we get
// input_output_iterator_tag, because the standard hierarchy has a
// sudden anomalous distinction between readability and
// writability at the level of input iterator/output iterator.
template <>
struct iterator_tag_base<
access_c<(readable_iterator|lvalue_iterator)>
, single_pass_traversal_tag
>
{
typedef std::input_iterator_tag type;
};
} // namespace detail
template <class Iterator>
struct access_category
: detail::tag_access_category<
typename detail::iterator_traits<Iterator>::iterator_category
, typename detail::iterator_traits<Iterator>::reference
//
// Convert a "strictly old-style" iterator category to a traversal
// tag. This is broken out into a separate metafunction to reduce
// the cost of instantiating iterator_category_to_traversal, below,
// for new-style types.
//
template <class Cat>
struct old_style_category_to_traversal
: mpl::apply_if<
is_convertible<Cat,std::random_access_iterator_tag>
, mpl::identity<random_access_traversal_tag>
, mpl::apply_if<
is_convertible<Cat,std::bidirectional_iterator_tag>
, mpl::identity<bidirectional_traversal_tag>
, mpl::apply_if<
is_convertible<Cat,std::forward_iterator_tag>
, mpl::identity<forward_traversal_tag>
, mpl::apply_if<
is_convertible<Cat,std::input_iterator_tag>
, mpl::identity<single_pass_traversal_tag>
, mpl::apply_if<
is_convertible<Cat,std::output_iterator_tag>
, mpl::identity<incrementable_traversal_tag>
, void
>
>
>
>
>
{};
} // namespace detail
template <class Iterator>
struct traversal_category
: detail::tag_traversal_category<
typename detail::iterator_traits<Iterator>::iterator_category
>
{
};
//
// Convert an iterator category into a traversal tag
//
template <class Cat>
struct iterator_category_to_traversal
: mpl::apply_if< // if already convertible to a traversal tag, we're done.
is_convertible<Cat,incrementable_traversal_tag>
, mpl::identity<Cat>
, detail::old_style_category_to_traversal<Cat>
>
{};
//
// To be used for a new-style iterator's iterator_category; provides
// implicit conversion to the appropriate old-style iterator category.
//
// If Value is const the result will not be convertible to
// output_iterator_tag.
//
// Otherwise, if Traversal == single_pass_traversal_tag, the following
// conditions will result in a tag that is convertible both to
// input_iterator_tag and output_iterator_tag:
//
// 1. Reference is a reference to non-const
// 2. Reference is not a reference and is convertible to Value
//
template <class Value, class Reference, class Traversal>
struct iterator_tag
: detail::old_iterator_category<Value, Reference, Traversal>::type
{
operator Traversal() { return Traversal(); }
# if 0
typedef typename detail::old_iterator_category<
Value, Reference, Traversal
>::type old_category;
operator old_category() const { return old_category(); }
# endif
};
// Trait to get an iterator's traversal category
template <class Iterator = mpl::_1>
struct iterator_traversal
: iterator_category_to_traversal<
typename boost::detail::iterator_traits<Iterator>::iterator_category
>
{};
# ifdef BOOST_MPL_NO_FULL_LAMBDA_SUPPORT
// Hack because BOOST_MPL_AUX_LAMBDA_SUPPORT doesn't seem to work
// out well. Instantiating the nested apply template also
// requires instantiating iterator_traits on the
// placeholder. Instead we just specialize it as a metafunction
// class.
template <>
struct access_category<mpl::_1>
{
template <class T>
struct apply : access_category<T>
{};
};
template <>
struct traversal_category<mpl::_1>
{
template <class T>
struct apply : traversal_category<T>
{};
};
# endif
# if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
template <typename T>
struct access_category<T*>
: mpl::if_<
is_const<T>
, detail::access_c<(readable_iterator|lvalue_iterator)>
, detail::access_c<(readable_iterator|writable_iterator|lvalue_iterator)>
>
{
};
template <typename T>
struct traversal_category<T*>
{
typedef random_access_traversal_tag type;
};
# endif
template <unsigned Access, class TraversalTag>
struct iterator_tag
: detail::iterator_tag_base<
typename detail::max_known_access_tag<detail::access_c<Access> >::type::value
, typename detail::max_known_traversal_tag<TraversalTag>::type
>::type
{
typedef detail::access_c<(Access & ~lvalue_iterator)> access_type;
BOOST_STATIC_CONSTANT(iterator_access, value = (iterator_access)(Access & ~lvalue_iterator));
typedef TraversalTag traversal;
};
namespace detail
{
# ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
// Hack because BOOST_MPL_AUX_LAMBDA_SUPPORT doesn't seem to work
// out well. Instantiating the nested apply template also
// requires instantiating iterator_traits on the
// placeholder. Instead we just specialize it as a metafunction
// class.
template <>
struct iterator_traversal<mpl::_1>
{
template <class T>
struct is_boost_iterator_tag
: mpl::false_ {};
template <unsigned A, class T>
struct is_boost_iterator_tag<iterator_tag<A,T> >
: mpl::true_ {};
# else
template <class T>
struct is_boost_iterator_tag
{
typedef char (&yes)[1];
typedef char (&no)[2];
template <unsigned A, class U>
static yes test(mpl::identity<iterator_tag<A,U> >*);
static no test(...);
static mpl::identity<T>* inst;
BOOST_STATIC_CONSTANT(bool, value = sizeof(test(inst)) == sizeof(yes));
typedef mpl::bool_<value> type;
};
struct apply : iterator_traversal<T>
{};
};
template <>
struct iterator_traversal<mpl::_>
: iterator_traversal<mpl::_1>
{};
# endif
}
} // namespace boost