#ifndef BOOST_RANGE_MFC_HPP
#define BOOST_RANGE_MFC_HPP




// Boost.Range MFC Extension
//
// Copyright Shunsuke Sogame 2005-2006.
// Distributed under the Boost Software License, Version 1.0. 
// (See accompanying file LICENSE_1_0.txt or copy at 
// http://www.boost.org/LICENSE_1_0.txt)




// config
//


#include <afx.h> // _MFC_VER


#if !defined(BOOST_RANGE_MFC_NO_CPAIR)
    #if (_MFC_VER < 0x0700) // dubious
        #define BOOST_RANGE_MFC_NO_CPAIR
    #endif
#endif


#if !defined(BOOST_RANGE_MFC_HAS_LEGACY_STRING)
    #if (_MFC_VER < 0x0700) // dubious
        #define BOOST_RANGE_MFC_HAS_LEGACY_STRING
    #endif
#endif


// A const collection of old MFC doesn't return const reference.
//
#if !defined(BOOST_RANGE_MFC_CONST_COL_RETURNS_NON_REF)
    #if (_MFC_VER < 0x0700) // dubious
        #define BOOST_RANGE_MFC_CONST_COL_RETURNS_NON_REF
    #endif
#endif




// forward declarations
//


template< class Type, class ArgType >
class CArray;

template< class Type, class ArgType >
class CList;

template< class Key, class ArgKey, class Mapped, class ArgMapped >
class CMap;

template< class BaseClass, class PtrType >
class CTypedPtrArray;

template< class BaseClass, class PtrType >
class CTypedPtrList;

template< class BaseClass, class KeyPtrType, class MappedPtrType >
class CTypedPtrMap;




// extended customizations
//


#include <cstddef> // ptrdiff_t
#include <utility> // pair
#include <boost/assert.hpp>
#include <boost/mpl/if.hpp>
#include <boost/range/atl.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/const_iterator.hpp>
#include <boost/range/detail/microsoft.hpp>
#include <boost/range/end.hpp>
#include <boost/iterator/iterator_adaptor.hpp>
#include <boost/iterator/iterator_categories.hpp>
#include <boost/iterator/iterator_facade.hpp>
#include <boost/iterator/transform_iterator.hpp>
#include <boost/type_traits/is_const.hpp>
#include <boost/type_traits/remove_pointer.hpp>
#include <boost/utility/addressof.hpp>
#include <afx.h> // legacy CString
#include <afxcoll.h> // CXXXArray, CXXXList, CMapXXXToXXX
#include <tchar.h>


namespace boost { namespace range_detail_microsoft {


    // mfc_ptr_array_iterator
    //
    // 'void **' is not convertible to 'void const **',
    // so we define...
    //

    template< class ArrayT, class PtrType >
    struct mfc_ptr_array_iterator;

    template< class ArrayT, class PtrType >
    struct mfc_ptr_array_iterator_super
    {
        typedef iterator_adaptor<
            mfc_ptr_array_iterator<ArrayT, PtrType>,
            std::ptrdiff_t, // Base!
            PtrType,        // Value
            random_access_traversal_tag,
            use_default,
            std::ptrdiff_t  // Difference
        > type;
    };

    template< class ArrayT, class PtrType >
    struct mfc_ptr_array_iterator :
        mfc_ptr_array_iterator_super<ArrayT, PtrType>::type
    {
    private:
        typedef mfc_ptr_array_iterator self_t;
        typedef typename mfc_ptr_array_iterator_super<ArrayT, PtrType>::type super_t;
        typedef typename super_t::reference ref_t;

    public:
        explicit mfc_ptr_array_iterator()
        { }

        explicit mfc_ptr_array_iterator(ArrayT& arr, INT_PTR index) :
            super_t(index), m_parr(boost::addressof(arr))
        { }

    template< class, class > friend struct mfc_ptr_array_iterator;
        template< class ArrayT_, class PtrType_ >
        mfc_ptr_array_iterator(mfc_ptr_array_iterator<ArrayT_, PtrType_> const& other) :
            super_t(other.base()), m_parr(other.m_parr)
        { }

    private:
        ArrayT *m_parr;

    friend class iterator_core_access;
        ref_t dereference() const
        {
            BOOST_ASSERT(0 <= this->base() && this->base() < m_parr->GetSize() && "out of range");
            return *( m_parr->GetData() + this->base() );
        }

        bool equal(self_t const& other) const
        {
            BOOST_ASSERT(m_parr == other.m_parr && "iterators incompatible");
            return this->base() == other.base();
        }
    };

    struct mfc_ptr_array_functions
    {
        template< class Iterator, class X >
        Iterator begin(X& x)
        {
            return Iterator(x, 0);
        }

        template< class Iterator, class X >
        Iterator end(X& x)
        {
            return Iterator(x, x.GetSize());
        }
    };


    // arrays
    //

    template< >
    struct customization< ::CByteArray > :
        array_functions
    {
        template< class X >
        struct meta
        {
            typedef BYTE val_t;

            typedef val_t *mutable_iterator;
            typedef val_t const *const_iterator;
        };
    };


    template< >
    struct customization< ::CDWordArray > :
        array_functions
    {
        template< class X >
        struct meta
        {
            typedef DWORD val_t;

            typedef val_t *mutable_iterator;
            typedef val_t const *const_iterator;
        };
    };


    template< >
    struct customization< ::CObArray > :
        mfc_ptr_array_functions
    {
        template< class X >
        struct meta
        {
            typedef mfc_ptr_array_iterator<X, CObject *> mutable_iterator;
            typedef mfc_ptr_array_iterator<X const, CObject const *> const_iterator;
        };
    };


    template< >
    struct customization< ::CPtrArray > :
        mfc_ptr_array_functions
    {
        template< class X >
        struct meta
        {
            typedef mfc_ptr_array_iterator<X, void *> mutable_iterator;
            typedef mfc_ptr_array_iterator<X const, void const *> const_iterator;
        };
    };


    template< >
    struct customization< ::CStringArray > :
        array_functions
    {
        template< class X >
        struct meta
        {
            typedef ::CString val_t;

            typedef val_t *mutable_iterator;
            typedef val_t const *const_iterator;
        };
    };


    template< >
    struct customization< ::CUIntArray > :
        array_functions
    {
        template< class X >
        struct meta
        {
            typedef UINT val_t;

            typedef val_t *mutable_iterator;
            typedef val_t const *const_iterator;
        };
    };


    template< >
    struct customization< ::CWordArray > :
        array_functions
    {
        template< class X >
        struct meta
        {
            typedef WORD val_t;

            typedef val_t *mutable_iterator;
            typedef val_t const *const_iterator;
        };
    };


    // lists
    //

    template< >
    struct customization< ::CObList > :
        list_functions
    {
        template< class X >
        struct meta
        {
            typedef list_iterator<X, ::CObject *> mutable_iterator;
            // const CObList and const CPtrList both return a value (and probably always will)
            typedef list_iterator<X const, ::CObject const * const, ::CObject const * const> const_iterator;
        };
    };


    template< >
    struct customization< ::CPtrList > :
        list_functions
    {
        template< class X >
        struct meta
        {
            typedef list_iterator<X, void *> mutable_iterator;
            // const CObList and const CPtrList both return a value (and probably always will)
            typedef list_iterator<X const, void const * const, void const * const> const_iterator;
        };
    };


    template< >
    struct customization< ::CStringList > :
        list_functions
    {
        template< class X >
        struct meta
        {
            typedef ::CString val_t;

            typedef list_iterator<X, val_t> mutable_iterator;
    #if !defined(BOOST_RANGE_MFC_CONST_COL_RETURNS_NON_REF)
            typedef list_iterator<X const, val_t const> const_iterator;
    #else
            typedef list_iterator<X const, val_t const, val_t const> const_iterator;
    #endif
        };
    };


    // mfc_map_iterator
    //

    template< class MapT, class KeyT, class MappedT >
    struct mfc_map_iterator;

    template< class MapT, class KeyT, class MappedT >
    struct mfc_map_iterator_super
    {
        typedef iterator_facade<
            mfc_map_iterator<MapT, KeyT, MappedT>,
            std::pair<KeyT, MappedT>,
            forward_traversal_tag,
            std::pair<KeyT, MappedT> const
        > type;
    };

    template< class MapT, class KeyT, class MappedT >
    struct mfc_map_iterator :
        mfc_map_iterator_super<MapT, KeyT, MappedT>::type
    {
    private:
        typedef mfc_map_iterator self_t;
        typedef typename mfc_map_iterator_super<MapT, KeyT, MappedT>::type super_t;
        typedef typename super_t::reference ref_t;

    public:
        explicit mfc_map_iterator()
        { }

        explicit mfc_map_iterator(MapT const& map, POSITION pos) :
            m_pmap(boost::addressof(map)), m_posNext(pos)
        {
            increment();
        }

        explicit mfc_map_iterator(MapT const& map) :
            m_pmap(&map), m_pos(0) // end iterator
        { }

    template< class, class, class > friend struct mfc_map_iterator;
        template< class MapT_, class KeyT_, class MappedT_>
        mfc_map_iterator(mfc_map_iterator<MapT_, KeyT_, MappedT_> const& other) :
            m_pmap(other.m_pmap),
            m_pos(other.m_pos), m_posNext(other.m_posNext),
            m_key(other.m_key), m_mapped(other.m_mapped)
        { }

    private:
        MapT const *m_pmap;
        POSITION m_pos, m_posNext;
        KeyT m_key; MappedT m_mapped;

    friend class iterator_core_access;
        ref_t dereference() const
        {
            BOOST_ASSERT(m_pos != 0 && "out of range");
            return std::make_pair(m_key, m_mapped);
        }

        void increment()
        {
            BOOST_ASSERT(m_pos != 0 && "out of range");

            if (m_posNext == 0) {
                m_pos = 0;
                return;
            }

            m_pos = m_posNext;
            m_pmap->GetNextAssoc(m_posNext, m_key, m_mapped);
        }

        bool equal(self_t const& other) const
        {
            BOOST_ASSERT(m_pmap == other.m_pmap && "iterators incompatible");
            return m_pos == other.m_pos;
        }
    };

    struct mfc_map_functions
    {
        template< class Iterator, class X >
        Iterator begin(X& x)
        {
            return Iterator(x, x.GetStartPosition());
        }

        template< class Iterator, class X >
        Iterator end(X& x)
        {
            return Iterator(x);
        }
    };


#if !defined(BOOST_RANGE_MFC_NO_CPAIR)


    // mfc_cpair_map_iterator
    //
    // used by ::CMap and ::CMapStringToString
    //

    template< class MapT, class PairT >
    struct mfc_cpair_map_iterator;

    template< class MapT, class PairT >
    struct mfc_pget_map_iterator_super
    {
        typedef iterator_facade<
            mfc_cpair_map_iterator<MapT, PairT>,
            PairT,
            forward_traversal_tag
        > type;
    };

    template< class MapT, class PairT >
    struct mfc_cpair_map_iterator :
        mfc_pget_map_iterator_super<MapT, PairT>::type
    {
    private:
        typedef mfc_cpair_map_iterator self_t;
        typedef typename mfc_pget_map_iterator_super<MapT, PairT>::type super_t;
        typedef typename super_t::reference ref_t;

    public:
        explicit mfc_cpair_map_iterator()
        { }

        explicit mfc_cpair_map_iterator(MapT& map, PairT *pp) :
            m_pmap(boost::addressof(map)), m_pp(pp)
        { }

    template< class, class > friend struct mfc_cpair_map_iterator;
        template< class MapT_, class PairT_>
        mfc_cpair_map_iterator(mfc_cpair_map_iterator<MapT_, PairT_> const& other) :
            m_pmap(other.m_pmap), m_pp(other.m_pp)
        { }

    private:
        MapT  *m_pmap;
        PairT *m_pp;

    friend class iterator_core_access;
        ref_t dereference() const
        {
            BOOST_ASSERT(m_pp != 0 && "out of range");
            return *m_pp;
        }

        void increment()
        {
            BOOST_ASSERT(m_pp != 0 && "out of range");
            m_pp = m_pmap->PGetNextAssoc(m_pp);
        }

        bool equal(self_t const& other) const
        {
            BOOST_ASSERT(m_pmap == other.m_pmap && "iterators incompatible");
            return m_pp == other.m_pp;
        }
    };

    struct mfc_cpair_map_functions
    {
        template< class Iterator, class X >
        Iterator begin(X& x)
        {
            // Workaround:
            // Assertion fails if empty.
            // MFC document is wrong.
    #if !defined(NDEBUG)
            if (x.GetCount() == 0) 
                return Iterator(x, 0);
    #endif

            return Iterator(x, x.PGetFirstAssoc());
        }

        template< class Iterator, class X >
        Iterator end(X& x)
        {
            return Iterator(x, 0);
        }
    };


#endif // !defined(BOOST_RANGE_MFC_NO_CPAIR)


    // maps
    //

    template< >
    struct customization< ::CMapPtrToWord > :
        mfc_map_functions
    {
        template< class X >
        struct meta
        {
            typedef void *key_t;
            typedef WORD mapped_t;

            typedef mfc_map_iterator<X, key_t, mapped_t> mutable_iterator;
            typedef mutable_iterator const_iterator;
        };
    };


    template< >
    struct customization< ::CMapPtrToPtr > :
        mfc_map_functions
    {
        template< class X >
        struct meta
        {
            typedef void *key_t;
            typedef void *mapped_t;

            typedef mfc_map_iterator<X, key_t, mapped_t> mutable_iterator;
            typedef mutable_iterator const_iterator;
        };
    };


    template< >
    struct customization< ::CMapStringToOb > :
        mfc_map_functions
    {
        template< class X >
        struct meta
        {
            typedef ::CString key_t;
            typedef ::CObject *mapped_t;

            typedef mfc_map_iterator<X, key_t, mapped_t> mutable_iterator;
            typedef mutable_iterator const_iterator;
        };
    };


    template< >
    struct customization< ::CMapStringToPtr > :
        mfc_map_functions
    {
        template< class X >
        struct meta
        {
            typedef ::CString key_t;
            typedef void *mapped_t;

            typedef mfc_map_iterator<X, key_t, mapped_t> mutable_iterator;
            typedef mutable_iterator const_iterator;
        };
    };


    template< >
    struct customization< ::CMapStringToString > :
    #if !defined(BOOST_RANGE_MFC_NO_CPAIR)
        mfc_cpair_map_functions
    #else
        mfc_map_functions
    #endif
    {
        template< class X >
        struct meta
        {
    #if !defined(BOOST_RANGE_MFC_NO_CPAIR)
            typedef typename X::CPair pair_t;

            typedef mfc_cpair_map_iterator<X, pair_t> mutable_iterator;
            typedef mfc_cpair_map_iterator<X const, pair_t const> const_iterator;
    #else
            typedef ::CString key_t;
            typedef ::CString mapped_t;

            typedef mfc_map_iterator<X, key_t, mapped_t> mutable_iterator;
            typedef mutable_iterator const_iterator;
    #endif
        };
    };


    template< >
    struct customization< ::CMapWordToOb > :
        mfc_map_functions
    {
        template< class X >
        struct meta
        {
            typedef WORD key_t;
            typedef ::CObject *mapped_t;

            typedef mfc_map_iterator<X, key_t, mapped_t> mutable_iterator;
            typedef mutable_iterator const_iterator;
        };
    };


    template< >
    struct customization< ::CMapWordToPtr > :
        mfc_map_functions
    {
        template< class X >
        struct meta
        {
            typedef WORD key_t;
            typedef void *mapped_t;

            typedef mfc_map_iterator<X, key_t, mapped_t> mutable_iterator;
            typedef mutable_iterator const_iterator;
        };
    };


    // templates
    //

    template< class Type, class ArgType >
    struct customization< ::CArray<Type, ArgType> > :
        array_functions
    {
        template< class X >
        struct meta
        {
            typedef Type val_t;

            typedef val_t *mutable_iterator;
            typedef val_t const *const_iterator;
        };
    };


    template< class Type, class ArgType >
    struct customization< ::CList<Type, ArgType> > :
        list_functions
    {
        template< class X >
        struct meta
        {
            typedef Type val_t;

            typedef list_iterator<X, val_t> mutable_iterator;
    #if !defined(BOOST_RANGE_MFC_CONST_COL_RETURNS_NON_REF)
            typedef list_iterator<X const, val_t const> const_iterator;
    #else
            typedef list_iterator<X const, val_t const, val_t const> const_iterator;
    #endif
        };
    };


    template< class Key, class ArgKey, class Mapped, class ArgMapped >
    struct customization< ::CMap<Key, ArgKey, Mapped, ArgMapped> > :
    #if !defined(BOOST_RANGE_MFC_NO_CPAIR)
        mfc_cpair_map_functions
    #else
        mfc_map_functions
    #endif
    {
        template< class X >
        struct meta
        {
    #if !defined(BOOST_RANGE_MFC_NO_CPAIR)
            typedef typename X::CPair pair_t;

            typedef mfc_cpair_map_iterator<X, pair_t> mutable_iterator;
            typedef mfc_cpair_map_iterator<X const, pair_t const> const_iterator;
    #else
            typedef Key key_t;
            typedef Mapped mapped_t;

            typedef mfc_map_iterator<X, key_t, mapped_t> mutable_iterator;
            typedef mutable_iterator const_iterator;
    #endif            
        };
    };


    template< class BaseClass, class PtrType >
    struct customization< ::CTypedPtrArray<BaseClass, PtrType> >
    {
        template< class X >
        struct fun
        {
            typedef typename remove_pointer<PtrType>::type val_t;

            typedef typename mpl::if_< is_const<X>,
                val_t const,
                val_t
            >::type val_t_;

            typedef val_t_ * const result_type;

            template< class PtrType_ >
            result_type operator()(PtrType_ p) const
            {
                return static_cast<result_type>(p);
            }
        };

        template< class X >
        struct meta
        {
            typedef typename compatible_mutable_iterator<BaseClass>::type miter_t;
            typedef typename range_const_iterator<BaseClass>::type citer_t;

            typedef transform_iterator<fun<X>, miter_t> mutable_iterator;
            typedef transform_iterator<fun<X const>, citer_t> const_iterator;
        };

        template< class Iterator, class X >
        Iterator begin(X& x)
        {
            return Iterator(boost::begin<BaseClass>(x), fun<X>());
        }

        template< class Iterator, class X >
        Iterator end(X& x)
        {
            return Iterator(boost::end<BaseClass>(x), fun<X>());
        }
    };


    template< class BaseClass, class PtrType >
    struct customization< ::CTypedPtrList<BaseClass, PtrType> > :
        list_functions
    {
        template< class X >
        struct meta
        {
            typedef typename remove_pointer<PtrType>::type val_t;

            // not l-value
            typedef list_iterator<X, val_t * const, val_t * const> mutable_iterator;
            typedef list_iterator<X const, val_t const * const, val_t const * const> const_iterator;
        };
    };


    template< class BaseClass, class KeyPtrType, class MappedPtrType >
    struct customization< ::CTypedPtrMap<BaseClass, KeyPtrType, MappedPtrType> > :
        mfc_map_functions
    {
        template< class X >
        struct meta
        {
            typedef mfc_map_iterator<X, KeyPtrType, MappedPtrType> mutable_iterator;
            typedef mutable_iterator const_iterator;
        };
    };


    // strings
    //

#if defined(BOOST_RANGE_MFC_HAS_LEGACY_STRING)

    template< >
    struct customization< ::CString >
    {
        template< class X >
        struct meta
        {
            // LPTSTR/LPCTSTR is not always defined in <tchar.h>.
            typedef TCHAR *mutable_iterator;
            typedef TCHAR const *const_iterator;
        };

        template< class Iterator, class X >
        typename mutable_<Iterator, X>::type begin(X& x)
        {
            return x.GetBuffer(0);
        }

        template< class Iterator, class X >
        Iterator begin(X const& x)
        {
            return x;
        }

        template< class Iterator, class X >
        Iterator end(X& x)
        {
            return begin<Iterator>(x) + x.GetLength();
        }
    };

#endif // defined(BOOST_RANGE_MFC_HAS_LEGACY_STRING)


} } // namespace boost::range_detail_microsoft




// range customizations
//


// arrays
//
BOOST_RANGE_DETAIL_MICROSOFT_CUSTOMIZATION_TYPE(
    boost::range_detail_microsoft::using_type_as_tag,
    BOOST_PP_NIL, CByteArray
)

BOOST_RANGE_DETAIL_MICROSOFT_CUSTOMIZATION_TYPE(
    boost::range_detail_microsoft::using_type_as_tag,
    BOOST_PP_NIL, CDWordArray
)

BOOST_RANGE_DETAIL_MICROSOFT_CUSTOMIZATION_TYPE(
    boost::range_detail_microsoft::using_type_as_tag,
    BOOST_PP_NIL, CStringArray
)

BOOST_RANGE_DETAIL_MICROSOFT_CUSTOMIZATION_TYPE(
    boost::range_detail_microsoft::using_type_as_tag,
    BOOST_PP_NIL, CUIntArray
)

BOOST_RANGE_DETAIL_MICROSOFT_CUSTOMIZATION_TYPE(
    boost::range_detail_microsoft::using_type_as_tag,
    BOOST_PP_NIL, CWordArray
)


// lists
//
BOOST_RANGE_DETAIL_MICROSOFT_CUSTOMIZATION_TYPE(
    boost::range_detail_microsoft::using_type_as_tag,
    BOOST_PP_NIL, CObList
)

BOOST_RANGE_DETAIL_MICROSOFT_CUSTOMIZATION_TYPE(
    boost::range_detail_microsoft::using_type_as_tag,
    BOOST_PP_NIL, CPtrList
)

BOOST_RANGE_DETAIL_MICROSOFT_CUSTOMIZATION_TYPE(
    boost::range_detail_microsoft::using_type_as_tag,
    BOOST_PP_NIL, CStringList
)

BOOST_RANGE_DETAIL_MICROSOFT_CUSTOMIZATION_TYPE(
    boost::range_detail_microsoft::using_type_as_tag,
    BOOST_PP_NIL, CObArray
)

BOOST_RANGE_DETAIL_MICROSOFT_CUSTOMIZATION_TYPE(
    boost::range_detail_microsoft::using_type_as_tag,
    BOOST_PP_NIL, CPtrArray
)


// maps
//
BOOST_RANGE_DETAIL_MICROSOFT_CUSTOMIZATION_TYPE(
    boost::range_detail_microsoft::using_type_as_tag,
    BOOST_PP_NIL, CMapPtrToWord
)

BOOST_RANGE_DETAIL_MICROSOFT_CUSTOMIZATION_TYPE(
    boost::range_detail_microsoft::using_type_as_tag,
    BOOST_PP_NIL, CMapPtrToPtr
)

BOOST_RANGE_DETAIL_MICROSOFT_CUSTOMIZATION_TYPE(
    boost::range_detail_microsoft::using_type_as_tag,
    BOOST_PP_NIL, CMapStringToOb
)

BOOST_RANGE_DETAIL_MICROSOFT_CUSTOMIZATION_TYPE(
    boost::range_detail_microsoft::using_type_as_tag,
    BOOST_PP_NIL, CMapStringToPtr
)

BOOST_RANGE_DETAIL_MICROSOFT_CUSTOMIZATION_TYPE(
    boost::range_detail_microsoft::using_type_as_tag,
    BOOST_PP_NIL, CMapStringToString
)

BOOST_RANGE_DETAIL_MICROSOFT_CUSTOMIZATION_TYPE(
    boost::range_detail_microsoft::using_type_as_tag,
    BOOST_PP_NIL, CMapWordToOb
)

BOOST_RANGE_DETAIL_MICROSOFT_CUSTOMIZATION_TYPE(
    boost::range_detail_microsoft::using_type_as_tag,
    BOOST_PP_NIL, CMapWordToPtr
)


// templates
//
BOOST_RANGE_DETAIL_MICROSOFT_CUSTOMIZATION_TEMPLATE(
    boost::range_detail_microsoft::using_type_as_tag,
    BOOST_PP_NIL, CArray, 2
)

BOOST_RANGE_DETAIL_MICROSOFT_CUSTOMIZATION_TEMPLATE(
    boost::range_detail_microsoft::using_type_as_tag,
    BOOST_PP_NIL, CList, 2
)

BOOST_RANGE_DETAIL_MICROSOFT_CUSTOMIZATION_TEMPLATE(
    boost::range_detail_microsoft::using_type_as_tag,
    BOOST_PP_NIL, CMap, 4
)

BOOST_RANGE_DETAIL_MICROSOFT_CUSTOMIZATION_TEMPLATE(
    boost::range_detail_microsoft::using_type_as_tag,
    BOOST_PP_NIL, CTypedPtrArray, 2
)

BOOST_RANGE_DETAIL_MICROSOFT_CUSTOMIZATION_TEMPLATE(
    boost::range_detail_microsoft::using_type_as_tag,
    BOOST_PP_NIL, CTypedPtrList, 2
)

BOOST_RANGE_DETAIL_MICROSOFT_CUSTOMIZATION_TEMPLATE(
    boost::range_detail_microsoft::using_type_as_tag,
    BOOST_PP_NIL, CTypedPtrMap, 3
)


// strings
//
#if defined(BOOST_RANGE_MFC_HAS_LEGACY_STRING)

    BOOST_RANGE_DETAIL_MICROSOFT_CUSTOMIZATION_TYPE(
        boost::range_detail_microsoft::using_type_as_tag,
        BOOST_PP_NIL, CString
    )

#endif




#endif
