From b97ad86e9c0ada32654875a2bffb0a305b49bbcc Mon Sep 17 00:00:00 2001 From: Thomas Witt Date: Tue, 31 Dec 2002 14:25:30 +0000 Subject: [PATCH] Improved implementation documentation. More structured approach towards compiler deficiencies. [SVN r817] --- include/boost/iterator/iterator_adaptors.hpp | 201 +++++++++++++++++-- 1 file changed, 185 insertions(+), 16 deletions(-) diff --git a/include/boost/iterator/iterator_adaptors.hpp b/include/boost/iterator/iterator_adaptors.hpp index f81ff4d..02616df 100644 --- a/include/boost/iterator/iterator_adaptors.hpp +++ b/include/boost/iterator/iterator_adaptors.hpp @@ -15,13 +15,26 @@ #include "boost/type_traits/detail/bool_trait_def.hpp" #if BOOST_WORKAROUND(BOOST_MSVC, <= 1301) || BOOST_WORKAROUND(__GNUC__, <= 2 && __GNUC_MINOR__ <= 95) || BOOST_WORKAROUND(__MWERKS__, <= 0x3000) -# define BOOST_NO_SFINAE // "Substitution Failure Is Not An Error not implemented" +# define BOOST_NO_SFINAE // "Substitution Failure Is Not An Error not implemented" #endif +#if BOOST_WORKAROUND(BOOST_MSVC, <=1200) +# define BOOST_ARG_DEP_TYPENAME +#else +# define BOOST_ARG_DEP_TYPENAME typename +#endif + +#if BOOST_WORKAROUND(__MWERKS__, <=0x2407) +# define BOOST_NO_IS_CONVERTIBLE // "Convertible does not provide enough/is not working" +#endif + namespace boost { namespace detail { + // + // Base machinery for all kinds of enable if + // template struct enabled { @@ -32,6 +45,11 @@ namespace boost { }; }; + // + // For compilers that don't support "Substitution Failure Is Not An Error" + // enable_if falls back to always enabled. See comments + // on operator implementation for consequences. + // template<> struct enabled { @@ -39,27 +57,51 @@ namespace boost { struct base { #ifdef BOOST_NO_SFINAE - // Disable enable if for MSVC + typedef T type; - // This would give a nice error messages containing - // invalid overlaod, but has the big disadvantage that - // there is no reference to user code. + // This way to do it would give a nice error messages containing + // invalid overload, but has the big disadvantage that + // there is no reference to user code in the error message. + // // struct invalid_overload; // typedef invalid_overload type; + // #endif }; }; - struct enable_type {}; - + // + // Meta function that determines whether two + // iterator types are considered interoperable. + // + // Two iterator types A,B are considered interoperable if either + // A is convertible to B or vice versa. + // This interoperability definition is in sync with the + // standards requirements on constant/mutable container + // iterators (23.1 [lib.container.requirements]). + // + // For compilers that don't support is_convertible + // is_interoperable gives false positives. See comments + // on operator implementation for consequences. + // template struct is_interoperable : +#ifdef BOOST_NO_IS_CONVERTIBLE + mpl::true_c +#else mpl::logical_or< is_convertible< A, B >, is_convertible< B, A > > +#endif { }; + // + // enable if for use in operator implementation. + // + // enable_if_interoperable falls back to always enabled for compilers + // that don't support enable_if or is_convertible. + // template @@ -71,9 +113,62 @@ namespace boost { #endif }; + // + // Result type used in enable_if_convertible meta function. + // This can be an incomplete type, as only pointers to + // enable_if_convertible< ... >::type are used. + // We could have used void for this, but conversion to + // void* is just to easy. + // + struct enable_type; + } // namespace detail - + // + // enable_if for use in adapted iterators constructors. + // + // In order to provide interoperability between adapted constant and + // mutable iterators, adapted iterators will usually provide templated + // conversion constructors of the following form + // + // template + // class adapted_iterator : + // public iterator_adaptor< adapted_iterator, Iterator > + // { + // public: + // + // ... + // + // template + // adapted_iterator(OtherIterator const& it, + // typename enable_if_convertible::type* = 0); + // + // ... + // }; + // + // enable_if_convertible is used to remove those overloads from the overload + // set that cannot be instantiated. For all practical purposes only overloads + // for constant/mutable interaction will remain. This has the advantage that + // meta functions like boost::is_convertible do not return false positives, + // as they can only look at the signature of the conversion constructor + // and not at the actual instantiation. + // + // enable_if_interoperable can be safely used in user code. It falls back to + // always enabled for compilers that don't support enable_if or is_convertible. + // There is no need for compiler specific workarounds in user code. + // + // The operators implementation relies on boost::is_convertible not returning + // false positives for user/library defined iterator types. See comments + // on operator implementation for consequences. + // +#ifdef BOOST_NO_IS_CONVERTIBLE + template + struct enable_if_convertible + { + typedef detail::enable_type type; + }; +#else template struct enable_if_convertible : @@ -83,13 +178,14 @@ namespace boost { typedef typename detail::enabled< is_convertible::value >::template base::type type; #endif }; +#endif // // Helper class for granting access to the iterator core interface. // // The simple core interface is used by iterator_facade. The core - // interface should not be made public so that it does not clutter - // the public interface of user defined iterators. Instead iterator_core_access + // interface of a user/library defined iterator type should not be made public + // so that it does not clutter the public interface. Instead iterator_core_access // should be made friend so that iterator_facade can access the core // interface through iterator_core_access. // @@ -171,12 +267,72 @@ namespace boost { { }; -#if BOOST_WORKAROUND(BOOST_MSVC, <=1200) -#define BOOST_ARG_DEP_TYPENAME -#else -#define BOOST_ARG_DEP_TYPENAME typename -#endif - + // + // Operator implementation. The library supplied operators + // enables the user to provide fully interoperable constant/mutable + // iterator types. I.e. the library provides all operators + // for all mutable/constant iterator combinations. + // + // Note though that this kind of interoperability for constant/mutable + // iterators is not required by the standard for container iterators. + // All the standard asks for is a conversion mutable -> constant. + // Most standard library implementations nowadays provide fully interoperable + // iterator implementations, but there are still heavily used implementations + // that do not provide them. (Actually it's even worse, they do not provide + // them for only a few iterators.) + // + // ?? Maybe a BOOST_ITERATOR_NO_FULL_INTEROPERABILITY macro should + // enable the user to turn off mixed type operators + // + // The library takes care to provide only the right operator overloads. + // I.e. + // + // bool operator==(Iterator, Iterator); + // bool operator==(ConstIterator, Iterator); + // bool operator==(Iterator, ConstIterator); + // bool operator==(ConstIterator, ConstIterator); + // + // ... + // + // In order to do so it uses c++ idioms that are not yet widely supported + // by current compiler releases. The library is designed to degrade gracefully + // in the face of compiler deficiencies. In general compiler + // deficiencies result in less strict error checking and more obscure + // error messages, functionality is not affected. + // + // For full operation compiler support for "Substitution Failure Is Not An Error" + // (aka. enable_if) and boost::is_convertible is required. + // + // The following problems occur if support is lacking. + // + // Pseudo code + // + // --------------- + // AdaptorA a1; + // AdaptorA a2; + // + // // This will result in a no such overload error in full operation + // // If enable_if or is_convertible is not supported + // // The instantiation will fail with an error hopefully indicating that + // // there is no operator== for Iterator1, Iterator2 + // // The same will happen if no enable_if is used to remove + // // false overloads from the templated conversion constructor + // // of AdaptorA. + // + // a1 == a2; + // ---------------- + // + // AdaptorA a; + // AdaptorB b; + // + // // This will result in a no such overload error in full operation + // // If enable_if is not supported the static assert used + // // in the operator implementation will fail. + // // This will accidently work if is_convertible is not supported. + // + // a == b; + // ---------------- + // template inline @@ -664,5 +820,18 @@ namespace boost { } // namespace boost +// +// clean up local workaround macros +// + +#ifdef BOOST_NO_SFINAE +# undef BOOST_NO_SFINAE +#endif + +#undef BOOST_ARG_DEP_TYPENAME + +#ifdef BOOST_NO_IS_CONVERTIBLE +# undef BOOST_NO_IS_CONVERTIBLE +#endif #endif // BOOST_ITERATOR_ADAPTORS_HPP