$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
Subject: [Boost-commit] svn:boost r62579 - in trunk: boost/mpl boost/mpl/aux_/config libs/mpl/doc/src/refmanual libs/mpl/test
From: steven_at_[hidden]
Date: 2010-06-08 10:24:56
Author: steven_watanabe
Date: 2010-06-08 10:24:55 EDT (Tue, 08 Jun 2010)
New Revision: 62579
URL: http://svn.boost.org/trac/boost/changeset/62579
Log:
Add BOOST_MPL_HAS_XXX_TEMPLATE_DEF.  Fixes #861
Added:
   trunk/libs/mpl/doc/src/refmanual/CFG_NO_HAS_XXX_TEMPLATE.rst   (contents, props changed)
   trunk/libs/mpl/doc/src/refmanual/HAS_XXX_TEMPLATE_DEF.rst   (contents, props changed)
   trunk/libs/mpl/doc/src/refmanual/HAS_XXX_TEMPLATE_NAMED_DEF.rst   (contents, props changed)
Text files modified: 
   trunk/boost/mpl/aux_/config/has_xxx.hpp |     1                                         
   trunk/boost/mpl/has_xxx.hpp             |   557 ++++++++++++++++++++++++++++++++++++++++
   trunk/libs/mpl/test/has_xxx.cpp         |   206 ++++++++++++++                          
   trunk/libs/mpl/test/no_has_xxx.cpp      |     4                                         
   4 files changed, 768 insertions(+), 0 deletions(-)
Modified: trunk/boost/mpl/aux_/config/has_xxx.hpp
==============================================================================
--- trunk/boost/mpl/aux_/config/has_xxx.hpp	(original)
+++ trunk/boost/mpl/aux_/config/has_xxx.hpp	2010-06-08 10:24:55 EDT (Tue, 08 Jun 2010)
@@ -27,6 +27,7 @@
         )
 
 #   define BOOST_MPL_CFG_NO_HAS_XXX
+#   define BOOST_MPL_CFG_NO_HAS_XXX_TEMPLATE
 
 #endif
 
Modified: trunk/boost/mpl/has_xxx.hpp
==============================================================================
--- trunk/boost/mpl/has_xxx.hpp	(original)
+++ trunk/boost/mpl/has_xxx.hpp	2010-06-08 10:24:55 EDT (Tue, 08 Jun 2010)
@@ -4,6 +4,7 @@
 
 // Copyright Aleksey Gurtovoy 2002-2006
 // Copyright David Abrahams 2002-2003
+// Copyright Daniel Walker 2007
 //
 // Distributed under the Boost Software License, Version 1.0. 
 // (See accompanying file LICENSE_1_0.txt or copy at 
@@ -18,13 +19,18 @@
 #include <boost/mpl/bool.hpp>
 #include <boost/mpl/aux_/type_wrapper.hpp>
 #include <boost/mpl/aux_/yes_no.hpp>
+#include <boost/mpl/aux_/config/gcc.hpp>
 #include <boost/mpl/aux_/config/has_xxx.hpp>
 #include <boost/mpl/aux_/config/msvc_typename.hpp>
 #include <boost/mpl/aux_/config/msvc.hpp>
 #include <boost/mpl/aux_/config/static_constant.hpp>
 #include <boost/mpl/aux_/config/workaround.hpp>
 
+#include <boost/preprocessor/array/elem.hpp>
 #include <boost/preprocessor/cat.hpp>
+#include <boost/preprocessor/control/if.hpp>
+#include <boost/preprocessor/repetition/enum_params.hpp>
+#include <boost/preprocessor/repetition/enum_trailing_params.hpp>
 
 #if BOOST_WORKAROUND( __BORLANDC__, BOOST_TESTED_AT(0x590) )
 # include <boost/type_traits/is_class.hpp>
@@ -271,4 +277,555 @@
     BOOST_MPL_HAS_XXX_TRAIT_NAMED_DEF(BOOST_PP_CAT(has_,name), name, false) \
 /**/
 
+
+#if !defined(BOOST_MPL_CFG_NO_HAS_XXX_TEMPLATE)
+
+// Create boolean n-ary Metafunction to detect a nested template
+// member with n template parameters. This implementation is based on
+// a USENET newsgroup's posting by Aleksey Gurtovoy
+// (comp.lang.c++.moderated, 2002-03-19), Rani Sharoni's USENET
+// posting cited above, the non-template has_xxx implementations
+// above, and discussion on the Boost mailing list.
+
+#   if !defined(BOOST_MPL_HAS_XXX_NO_WRAPPED_TYPES)
+#     if BOOST_WORKAROUND(BOOST_MSVC, <= 1400)
+#       define BOOST_MPL_HAS_XXX_NO_WRAPPED_TYPES 1
+#     endif
+#   endif
+
+#   if !defined(BOOST_MPL_HAS_XXX_NO_EXPLICIT_TEST_FUNCTION)
+#     if (defined(BOOST_NO_EXPLICIT_FUNCTION_TEMPLATE_ARGUMENTS) \
+          || BOOST_WORKAROUND(BOOST_MPL_CFG_GCC, <= 0x0303))
+#       define BOOST_MPL_HAS_XXX_NO_EXPLICIT_TEST_FUNCTION 1
+#     endif
+#   endif
+
+#   if !defined(BOOST_MPL_HAS_XXX_NO_IMPLICIT_SUBSTITUTE_TEMPLATE)
+#     if BOOST_WORKAROUND(BOOST_MPL_CFG_GCC, <= 0x0303)
+#       define BOOST_MPL_HAS_XXX_NO_IMPLICIT_SUBSTITUTE_TEMPLATE 1
+#     endif
+#   endif
+
+#   if !defined(BOOST_MPL_HAS_XXX_NEEDS_TEMPLATE_SFINAE)
+#     if BOOST_WORKAROUND(BOOST_MSVC, <= 1400)
+#       define BOOST_MPL_HAS_XXX_NEEDS_TEMPLATE_SFINAE 1
+#     endif
+#   endif
+
+// NOTE: All internal implementation macros take a Boost.Preprocessor
+// array argument called args which contains the arguments passed to
+// HAS_XXX_TEMPLATE_NAMED_DEF and is of the following form.
+//               ( 4, ( trait, name, n, default_ ) )
+
+#   define BOOST_MPL_HAS_MEMBER_INTROSPECTION_NAME(args) \
+      BOOST_PP_CAT(BOOST_PP_ARRAY_ELEM(0, args) , _introspect) \
+    /**/
+
+#   define BOOST_MPL_HAS_MEMBER_INTROSPECTION_SUBSTITUTE_NAME(args) \
+      BOOST_PP_CAT(BOOST_PP_ARRAY_ELEM(0, args) , _substitute) \
+    /**/
+
+#   define BOOST_MPL_HAS_MEMBER_INTROSPECTION_TEST_NAME(args) \
+      BOOST_PP_CAT(BOOST_PP_ARRAY_ELEM(0, args) , _test) \
+    /**/
+
+// Thanks to Guillaume Melquiond for pointing out the need for the
+// "substitute" template as an argument to the overloaded test
+// functions to get SFINAE to work for member templates with the
+// correct name but incorrect arguments.
+#   define BOOST_MPL_HAS_MEMBER_SUBSTITUTE(args, substitute_macro) \
+      template< substitute_macro(args, V) > \
+      struct BOOST_MPL_HAS_MEMBER_INTROSPECTION_SUBSTITUTE_NAME(args) { \
+      }; \
+    /**/
+
+#   if !BOOST_MPL_HAS_XXX_NO_EXPLICIT_TEST_FUNCTION
+#     define BOOST_MPL_HAS_MEMBER_REJECT(args, member_macro) \
+        template< typename V > \
+        static boost::mpl::aux::no_tag \
+        BOOST_MPL_HAS_MEMBER_INTROSPECTION_TEST_NAME(args)(...); \
+      /**/
+#   else
+#     define BOOST_MPL_HAS_MEMBER_REJECT(args, member_macro) \
+        static boost::mpl::aux::no_tag \
+        BOOST_MPL_HAS_MEMBER_INTROSPECTION_TEST_NAME(args)(...); \
+      /**/
+#   endif
+
+#   if !BOOST_MPL_HAS_XXX_NO_WRAPPED_TYPES
+#     define BOOST_MPL_HAS_MEMBER_ACCEPT(args, member_macro) \
+        template< typename V > \
+        static boost::mpl::aux::yes_tag \
+        BOOST_MPL_HAS_MEMBER_INTROSPECTION_TEST_NAME(args)( \
+            boost::mpl::aux::type_wrapper< V > const volatile* \
+          , BOOST_MPL_HAS_MEMBER_INTROSPECTION_SUBSTITUTE_NAME(args) < \
+                member_macro(args, V, T) \
+            >* = 0 \
+        ); \
+      /**/
+#   else
+#     define BOOST_MPL_HAS_MEMBER_ACCEPT(args, member_macro) \
+        template< typename V > \
+        static boost::mpl::aux::yes_tag \
+        BOOST_MPL_HAS_MEMBER_INTROSPECTION_TEST_NAME(args)( \
+            V const volatile* \
+          , member_macro(args, V, T)* = 0 \
+        ); \
+      /**/
+#   endif
+
+#   if !BOOST_MPL_HAS_XXX_NO_EXPLICIT_TEST_FUNCTION
+#     define BOOST_MPL_HAS_MEMBER_TEST(args) \
+          sizeof(BOOST_MPL_HAS_MEMBER_INTROSPECTION_TEST_NAME(args)< U >(0)) \
+              == sizeof(boost::mpl::aux::yes_tag) \
+      /**/
+#   else
+#     if !BOOST_MPL_HAS_XXX_NO_WRAPPED_TYPES
+#       define BOOST_MPL_HAS_MEMBER_TEST(args) \
+          sizeof( \
+              BOOST_MPL_HAS_MEMBER_INTROSPECTION_TEST_NAME(args)( \
+                  static_cast< boost::mpl::aux::type_wrapper< U >* >(0) \
+              ) \
+          ) == sizeof(boost::mpl::aux::yes_tag) \
+        /**/
+#     else
+#       define BOOST_MPL_HAS_MEMBER_TEST(args) \
+          sizeof( \
+              BOOST_MPL_HAS_MEMBER_INTROSPECTION_TEST_NAME(args)( \
+                  static_cast< U* >(0) \
+              ) \
+          ) == sizeof(boost::mpl::aux::yes_tag) \
+        /**/
+#     endif
+#   endif
+
+#   define BOOST_MPL_HAS_MEMBER_INTROSPECT( \
+               args, substitute_macro, member_macro \
+           ) \
+      template< typename U > \
+      struct BOOST_MPL_HAS_MEMBER_INTROSPECTION_NAME(args) { \
+          BOOST_MPL_HAS_MEMBER_SUBSTITUTE(args, substitute_macro) \
+          BOOST_MPL_HAS_MEMBER_REJECT(args, member_macro) \
+          BOOST_MPL_HAS_MEMBER_ACCEPT(args, member_macro) \
+          BOOST_STATIC_CONSTANT( \
+              bool, value = BOOST_MPL_HAS_MEMBER_TEST(args) \
+          ); \
+          typedef boost::mpl::bool_< value > type; \
+      }; \
+    /**/
+
+#   define BOOST_MPL_HAS_MEMBER_IMPLEMENTATION( \
+               args, introspect_macro, substitute_macro, member_macro \
+           ) \
+      template< \
+          typename T \
+          BOOST_PP_ENUM_TRAILING_PARAMS( \
+              BOOST_PP_ARRAY_ELEM(2, args), typename T \
+          )  \
+        , typename fallback_ \
+              = boost::mpl::bool_< BOOST_PP_ARRAY_ELEM(3, args) > \
+      > \
+      class BOOST_PP_ARRAY_ELEM(0, args) { \
+          introspect_macro(args, substitute_macro, member_macro) \
+      public: \
+          static const bool value \
+              = BOOST_MPL_HAS_MEMBER_INTROSPECTION_NAME(args)< T >::value; \
+          typedef typename BOOST_MPL_HAS_MEMBER_INTROSPECTION_NAME(args)< \
+              T \
+          >::type type; \
+      }; \
+    /**/
+
+// For example,
+// BOOST_MPL_HAS_MEMBER_WITH_FUNCTION_SFINAE(
+//     (4, (has_xxx, xxx, 2, false))
+//   , BOOST_MPL_HAS_MEMBER_TEMPLATE_SUBSTITUTE_PARAMETER
+//   , BOOST_MPL_HAS_MEMBER_TEMPLATE_ACCESS
+// )
+// expands to something like the following...
+//
+// template<
+//     typename T , typename T0 , typename T1
+//   , typename fallback_ = boost::mpl::bool_< false >
+// >
+// class has_xxx {
+//     template< typename U >
+//     struct has_xxx_introspect {
+//         template< template< typename V0 , typename V1 > class V >
+//         struct has_xxx_substitute {
+//         };
+//
+//         template< typename V >
+//         static boost::mpl::aux::no_tag
+//         has_xxx_test(...);
+//
+//         template< typename V >
+//         static boost::mpl::aux::yes_tag
+//         has_xxx_test(
+//             boost::mpl::aux::type_wrapper< V > const volatile*
+//           , has_xxx_substitute < V::template xxx >* = 0
+//         );
+//
+//         static const bool value
+//             = sizeof(has_xxx_test< U >(0))
+//                   == sizeof(boost::mpl::aux::yes_tag);
+//         typedef boost::mpl::bool_< value > type;
+//     };
+// public:
+//     static const bool value = has_xxx_introspect< T >::value;
+//     typedef typename has_xxx_introspect< T >::type type;
+// };
+#   define BOOST_MPL_HAS_MEMBER_WITH_FUNCTION_SFINAE( \
+               args, substitute_macro, member_macro \
+           ) \
+      BOOST_MPL_HAS_MEMBER_IMPLEMENTATION( \
+          args \
+        , BOOST_MPL_HAS_MEMBER_INTROSPECT \
+        , substitute_macro \
+        , member_macro \
+      ) \
+    /**/
+
+#   if BOOST_MPL_HAS_XXX_NEEDS_TEMPLATE_SFINAE
+
+#     if !defined(BOOST_MPL_HAS_XXX_NEEDS_NAMESPACE_LEVEL_SUBSTITUTE)
+#       if BOOST_WORKAROUND(BOOST_MSVC, <= 1400)
+#         define BOOST_MPL_HAS_XXX_NEEDS_NAMESPACE_LEVEL_SUBSTITUTE 1
+#       endif
+#     endif
+
+#     if !BOOST_MPL_HAS_XXX_NEEDS_NAMESPACE_LEVEL_SUBSTITUTE
+#       define BOOST_MPL_HAS_MEMBER_INTROSPECTION_SUBSTITUTE_NAME_WITH_TEMPLATE_SFINAE( \
+                   args \
+               ) \
+          BOOST_MPL_HAS_MEMBER_INTROSPECTION_SUBSTITUTE_NAME(args) \
+        /**/
+#     else
+#       define BOOST_MPL_HAS_MEMBER_INTROSPECTION_SUBSTITUTE_NAME_WITH_TEMPLATE_SFINAE( \
+                   args \
+               ) \
+          BOOST_PP_CAT( \
+              boost_mpl_has_xxx_ \
+            , BOOST_MPL_HAS_MEMBER_INTROSPECTION_SUBSTITUTE_NAME(args) \
+          ) \
+        /**/
+#     endif
+
+#     define BOOST_MPL_HAS_MEMBER_INTROSPECTION_SUBSTITUTE_TAG_NAME( \
+                 args \
+             ) \
+        BOOST_PP_CAT( \
+            BOOST_MPL_HAS_MEMBER_INTROSPECTION_SUBSTITUTE_NAME_WITH_TEMPLATE_SFINAE( \
+                args \
+            ) \
+          , _tag \
+        ) \
+      /**/
+
+#     define BOOST_MPL_HAS_MEMBER_SUBSTITUTE_WITH_TEMPLATE_SFINAE( \
+                 args, substitute_macro \
+             ) \
+        typedef void \
+            BOOST_MPL_HAS_MEMBER_INTROSPECTION_SUBSTITUTE_TAG_NAME(args); \
+        template< substitute_macro(args, U) > \
+        struct BOOST_MPL_HAS_MEMBER_INTROSPECTION_SUBSTITUTE_NAME_WITH_TEMPLATE_SFINAE( \
+                args \
+               ) { \
+            typedef \
+                BOOST_MPL_HAS_MEMBER_INTROSPECTION_SUBSTITUTE_TAG_NAME(args) \
+                type; \
+        }; \
+      /**/
+
+#     define BOOST_MPL_HAS_MEMBER_REJECT_WITH_TEMPLATE_SFINAE( \
+                 args, member_macro \
+             ) \
+        template< \
+            typename U \
+            BOOST_PP_ENUM_TRAILING_PARAMS( \
+                BOOST_PP_ARRAY_ELEM(2, args), typename U \
+            ) \
+          , typename V \
+                = BOOST_MPL_HAS_MEMBER_INTROSPECTION_SUBSTITUTE_TAG_NAME(args) \
+        > \
+        struct BOOST_MPL_HAS_MEMBER_INTROSPECTION_TEST_NAME(args) { \
+            BOOST_STATIC_CONSTANT(bool, value = false); \
+            typedef boost::mpl::bool_< value > type; \
+        }; \
+      /**/
+
+#     define BOOST_MPL_HAS_MEMBER_ACCEPT_WITH_TEMPLATE_SFINAE( \
+                 args, member_macro \
+             ) \
+        template< \
+            typename U \
+            BOOST_PP_ENUM_TRAILING_PARAMS( \
+                BOOST_PP_ARRAY_ELEM(2, args), typename U \
+            ) \
+        > \
+        struct BOOST_MPL_HAS_MEMBER_INTROSPECTION_TEST_NAME(args)< \
+            U BOOST_PP_ENUM_TRAILING_PARAMS(BOOST_PP_ARRAY_ELEM(2, args), U) \
+          , typename \
+                BOOST_MPL_HAS_MEMBER_INTROSPECTION_SUBSTITUTE_NAME_WITH_TEMPLATE_SFINAE( \
+                    args \
+                )< \
+                    member_macro(args, U, U) \
+                >::type \
+        > { \
+            BOOST_STATIC_CONSTANT(bool, value = true); \
+            typedef boost::mpl::bool_< value > type; \
+        }; \
+      /**/
+
+#     define BOOST_MPL_HAS_MEMBER_BASIC_INTROSPECT_WITH_TEMPLATE_SFINAE( \
+                 args, substitute_macro, member_macro \
+             ) \
+        BOOST_MPL_HAS_MEMBER_REJECT_WITH_TEMPLATE_SFINAE(args, member_macro) \
+        BOOST_MPL_HAS_MEMBER_ACCEPT_WITH_TEMPLATE_SFINAE(args, member_macro) \
+        template< typename U > \
+        struct BOOST_MPL_HAS_MEMBER_INTROSPECTION_NAME(args) \
+            : BOOST_MPL_HAS_MEMBER_INTROSPECTION_TEST_NAME(args)< \
+                  U \
+                  BOOST_PP_ENUM_TRAILING_PARAMS( \
+                      BOOST_PP_ARRAY_ELEM(2, args) \
+                    , T \
+                  ) \
+              > { \
+        }; \
+      /**/
+
+#     if !BOOST_MPL_HAS_XXX_NEEDS_NAMESPACE_LEVEL_SUBSTITUTE
+#       define BOOST_MPL_HAS_MEMBER_INTROSPECT_WITH_TEMPLATE_SFINAE( \
+                   args, substitute_macro, member_macro \
+               ) \
+          BOOST_MPL_HAS_MEMBER_SUBSTITUTE_WITH_TEMPLATE_SFINAE( \
+              args, substitute_macro \
+          ) \
+          BOOST_MPL_HAS_MEMBER_BASIC_INTROSPECT_WITH_TEMPLATE_SFINAE( \
+              args, substitute_macro, member_macro \
+          ) \
+        /**/
+#     else
+#       define BOOST_MPL_HAS_MEMBER_INTROSPECT_WITH_TEMPLATE_SFINAE( \
+                   args, substitute_macro, member_macro \
+               ) \
+          BOOST_MPL_HAS_MEMBER_BASIC_INTROSPECT_WITH_TEMPLATE_SFINAE( \
+              args, substitute_macro, member_macro \
+          ) \
+        /**/
+#     endif
+
+// For example,
+// BOOST_MPL_HAS_MEMBER_WITH_TEMPLATE_SFINAE(
+//     (4, (has_xxx, xxx, 2, false))
+//   , BOOST_MPL_HAS_MEMBER_TEMPLATE_SUBSTITUTE_PARAMETER
+//   , BOOST_MPL_HAS_MEMBER_TEMPLATE_ACCESS
+// )
+// expands to something like the following...
+//
+// template<
+//     typename T , typename T0 , typename T1
+//   , typename fallback_ = boost::mpl::bool_< false >
+// >
+// class has_xxx {
+//     typedef void has_xxx_substitute_tag;
+//
+//     template< template< typename U0 , typename U1 > class U >
+//     struct has_xxx_substitute {
+//         typedef has_xxx_substitute_tag type;
+//     };
+//
+//     template<
+//         typename U , typename U0 , typename U1
+//       , typename V = has_xxx_substitute_tag
+//     >
+//     struct has_xxx_test {
+//         static const bool value = false;
+//         typedef boost::mpl::bool_< value > type;
+//     };
+//
+//     template< typename U , typename U0 , typename U1 >
+//     struct has_xxx_test<
+//         U , U0 , U1
+//       , typename has_xxx_substitute< U::template xxx >::type
+//     > {
+//         static const bool value = true;
+//         typedef boost::mpl::bool_< value > type;
+//     };
+//
+//     template< typename U >
+//     struct has_xxx_introspect : has_xxx_test< U , T0 , T1 > {
+//     };
+// public:
+//     static const bool value = has_xxx_introspect< T >::value;
+//     typedef typename has_xxx_introspect< T >::type type;
+// };
+//
+// Note that if BOOST_MPL_HAS_XXX_NEEDS_NAMESPACE_LEVEL_SUBSTITUTE is
+// defined BOOST_MPL_HAS_MEMBER_SUBSTITUTE_WITH_TEMPLATE_SFINAE needs
+// to be expanded at namespace level before
+// BOOST_MPL_HAS_MEMBER_WITH_TEMPLATE_SFINAE can be used.
+#     define BOOST_MPL_HAS_MEMBER_WITH_TEMPLATE_SFINAE( \
+                 args, substitute_macro, member_macro \
+             ) \
+        BOOST_MPL_HAS_MEMBER_IMPLEMENTATION( \
+            args \
+          , BOOST_MPL_HAS_MEMBER_INTROSPECT_WITH_TEMPLATE_SFINAE \
+          , substitute_macro \
+          , member_macro \
+        ) \
+      /**/
+
+#   endif // BOOST_MPL_HAS_XXX_NEEDS_TEMPLATE_SFINAE
+
+#   define BOOST_MPL_HAS_MEMBER_TEMPLATE_EXPLICIT_SUBSTITUTE_PARAMETER( \
+               args, param \
+           ) \
+      typename \
+    /**/
+
+#   if !BOOST_MPL_HAS_XXX_NO_IMPLICIT_SUBSTITUTE_TEMPLATE
+#     define BOOST_MPL_HAS_MEMBER_TEMPLATE_IMPLICIT_SUBSTITUTE_PARAMETER( \
+                 args, param \
+             ) \
+        template< \
+            BOOST_PP_ENUM_PARAMS(BOOST_PP_ARRAY_ELEM(2, args), typename param) \
+        > \
+        class param\
+      /**/
+
+// See comment at BOOST_MPL_HAS_MEMBER_TEMPLATE_ACCESS below.
+#     define BOOST_MPL_HAS_MEMBER_TEMPLATE_SUBSTITUTE_PARAMETER(args, param) \
+        BOOST_PP_IF( \
+            BOOST_PP_ARRAY_ELEM(2, args) \
+          , BOOST_MPL_HAS_MEMBER_TEMPLATE_IMPLICIT_SUBSTITUTE_PARAMETER \
+          , BOOST_MPL_HAS_MEMBER_TEMPLATE_EXPLICIT_SUBSTITUTE_PARAMETER \
+        ) ( args, param ) \
+      /**/
+#   else
+#     define BOOST_MPL_HAS_MEMBER_TEMPLATE_SUBSTITUTE_PARAMETER(args, param) \
+        BOOST_MPL_HAS_MEMBER_TEMPLATE_EXPLICIT_SUBSTITUTE_PARAMETER( \
+            args, param \
+        ) \
+      /**/
+#   endif
+
+#   define BOOST_MPL_HAS_MEMBER_TEMPLATE_EXPLICIT_ACCESS( \
+               args, class_type, param \
+           ) \
+      typename class_type::template BOOST_PP_ARRAY_ELEM(1, args)< \
+          BOOST_PP_ENUM_PARAMS(BOOST_PP_ARRAY_ELEM(2, args), param) \
+      > \
+    /**/
+
+#   if !BOOST_MPL_HAS_XXX_NO_IMPLICIT_SUBSTITUTE_TEMPLATE
+#     define BOOST_MPL_HAS_MEMBER_TEMPLATE_IMPLICIT_ACCESS( \
+               args, class_type, param \
+             ) \
+        class_type::template BOOST_PP_ARRAY_ELEM(1, args) \
+      /**/
+
+// Note: to recognize templates with no required arguments use
+// explicit access since a substitute template with no args cannot be
+// declared.
+#     define BOOST_MPL_HAS_MEMBER_TEMPLATE_ACCESS(args, class_type, param) \
+        BOOST_PP_IF( \
+            BOOST_PP_ARRAY_ELEM(2, args) \
+          , BOOST_MPL_HAS_MEMBER_TEMPLATE_IMPLICIT_ACCESS \
+          , BOOST_MPL_HAS_MEMBER_TEMPLATE_EXPLICIT_ACCESS \
+        ) ( args, class_type, param ) \
+      /**/
+#   else
+#     define BOOST_MPL_HAS_MEMBER_TEMPLATE_ACCESS(args, class_type, param) \
+        BOOST_MPL_HAS_MEMBER_TEMPLATE_EXPLICIT_ACCESS( \
+            args, class_type, param \
+        ) \
+      /**/
+#   endif
+
+#   if BOOST_WORKAROUND(BOOST_MSVC, <= 1400)
+// MSVC (7.1, 8.0) accepts the member template access syntax below
+// regardless of the member template's arity. introspect will reject
+// member templates with the wrong arity due to the substitute
+// template. Note that using this syntax also enables MSVC
+// template-based SFINAE to reject non-template members. This is
+// important because explicitly passing the template args will match
+// templates with the correct name and arguments but will cause ICE on
+// non-template members. However, MSVC nullary template-based SFINAE
+// (introspection for a member template with no required args) can not
+// reject non-template members, but MSVC function-based SFINAE
+// can. So, one of the two is chosen based on the number of required
+// template parameters.
+#     if !BOOST_WORKAROUND(BOOST_MSVC, < 1300)
+#       define BOOST_MPL_HAS_MEMBER_TEMPLATE_ACCESS_MSVC( \
+                   args, class_type, param \
+               ) \
+          typename class_type::template BOOST_PP_ARRAY_ELEM(1, args)< > \
+        /**/
+#     else
+#       define BOOST_MPL_HAS_MEMBER_TEMPLATE_ACCESS_MSVC( \
+                   args, class_type, param \
+               ) \
+          class_type::BOOST_PP_ARRAY_ELEM(1, agrs)< > \
+        /**/
+#     endif
+
+#     define BOOST_MPL_HAS_MEMBER_TEMPLATE_MSVC( \
+                 args, substitute_macro, member_macro \
+             ) \
+        BOOST_MPL_HAS_MEMBER_SUBSTITUTE_WITH_TEMPLATE_SFINAE( \
+            args, substitute_macro \
+        ) \
+        BOOST_PP_IF( \
+            BOOST_PP_ARRAY_ELEM(2, args) \
+          , BOOST_MPL_HAS_MEMBER_WITH_TEMPLATE_SFINAE \
+          , BOOST_MPL_HAS_MEMBER_WITH_FUNCTION_SFINAE \
+        ) ( \
+            args \
+          , substitute_macro \
+          , member_macro \
+        ) \
+      /**/
+#   endif
+
+#   if !BOOST_WORKAROUND(BOOST_MSVC, <= 1400)
+#     define BOOST_MPL_HAS_XXX_TEMPLATE_NAMED_DEF(trait, name, n, default_) \
+        BOOST_MPL_HAS_MEMBER_WITH_FUNCTION_SFINAE( \
+            ( 4, ( trait, name, n, default_ ) ) \
+          , BOOST_MPL_HAS_MEMBER_TEMPLATE_SUBSTITUTE_PARAMETER \
+          , BOOST_MPL_HAS_MEMBER_TEMPLATE_ACCESS \
+        ) \
+      /**/
+#   else
+#     define BOOST_MPL_HAS_XXX_TEMPLATE_NAMED_DEF(trait, name, n, default_) \
+        BOOST_MPL_HAS_MEMBER_TEMPLATE_MSVC( \
+            ( 4, ( trait, name, n, default_ ) ) \
+          , BOOST_MPL_HAS_MEMBER_TEMPLATE_SUBSTITUTE_PARAMETER \
+          , BOOST_MPL_HAS_MEMBER_TEMPLATE_ACCESS_MSVC \
+        ) \
+      /**/
+#   endif
+
+#else // BOOST_MPL_CFG_NO_HAS_XXX_TEMPLATE
+
+// placeholder implementation
+
+#   define BOOST_MPL_HAS_XXX_TEMPLATE_NAMED_DEF(trait, name, n, default_) \
+      template< typename T \
+                BOOST_PP_ENUM_TRAILING_PARAMS(n, typename U) \
+              , typename fallback_ = boost::mpl::bool_< default_ > > \
+      struct trait { \
+          BOOST_STATIC_CONSTANT(bool, value = fallback_::value); \
+          typedef fallback_ type; \
+      }; \
+    /**/
+
+#endif // BOOST_MPL_CFG_NO_HAS_XXX_TEMPLATE
+
+#   define BOOST_MPL_HAS_XXX_TEMPLATE_DEF(name, n) \
+      BOOST_MPL_HAS_XXX_TEMPLATE_NAMED_DEF( \
+          BOOST_PP_CAT(has_, name), name, n, false \
+      ) \
+    /**/
+
 #endif // BOOST_MPL_HAS_XXX_HPP_INCLUDED
Added: trunk/libs/mpl/doc/src/refmanual/CFG_NO_HAS_XXX_TEMPLATE.rst
==============================================================================
--- (empty file)
+++ trunk/libs/mpl/doc/src/refmanual/CFG_NO_HAS_XXX_TEMPLATE.rst	2010-06-08 10:24:55 EDT (Tue, 08 Jun 2010)
@@ -0,0 +1,32 @@
+.. Macros/Configuration//BOOST_MPL_CFG_NO_HAS_XXX_TEMPLATE |20
+
+.. Copyright Daniel Walker 2007.
+.. 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)
+
+BOOST_MPL_CFG_NO_HAS_XXX_TEMPLATE
+=================================
+
+Synopsis
+--------
+
+.. parsed-literal::
+
+    // #define BOOST_MPL_CFG_NO_HAS_XXX_TEMPLATE
+
+
+Description
+-----------
+
+``BOOST_MPL_CFG_NO_HAS_XXX_TEMPLATE`` is a boolean configuration
+macro signaling availability of the |BOOST_MPL_HAS_XXX_TEMPLATE_DEF| /
+|BOOST_MPL_HAS_XXX_TEMPLATE_NAMED_DEF| introspection macros'
+functionality on a particular compiler.
+
+
+See also
+--------
+
+|Macros|, |Configuration|, |BOOST_MPL_HAS_XXX_TEMPLATE_DEF|, |BOOST_MPL_HAS_XXX_TEMPLATE_NAMED_DEF|
+
Added: trunk/libs/mpl/doc/src/refmanual/HAS_XXX_TEMPLATE_DEF.rst
==============================================================================
--- (empty file)
+++ trunk/libs/mpl/doc/src/refmanual/HAS_XXX_TEMPLATE_DEF.rst	2010-06-08 10:24:55 EDT (Tue, 08 Jun 2010)
@@ -0,0 +1,125 @@
+.. Macros/Introspection//BOOST_MPL_HAS_XXX_TEMPLATE_DEF
+
+.. Copyright Daniel Walker 2007.
+.. 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)
+
+BOOST_MPL_HAS_XXX_TEMPLATE_DEF
+==============================
+
+Synopsis
+--------
+
+.. parsed-literal::
+
+    #define BOOST_MPL_HAS_XXX_TEMPLATE_DEF(name, n) \\
+        |unspecified-token-seq| \\
+    /\*\*/
+
+
+Description
+-----------
+
+Expands into the definition of a boolean n-ary |Metafunction|
+``has_name`` such that for any types ``x, a1, a2, ..., an``
+``has_name<x, a1, ..., an>::value == true`` if and only if ``x`` is a
+class type and has a nested template member ``x::template name<a1,
+..., an>``.
+
+On deficient compilers not capable of performing the detection,
+``has_name<x, a1, ..., an>::value`` always returns ``false``. A
+boolean configuration macro, |BOOST_MPL_CFG_NO_HAS_XXX_TEMPLATE|, is
+provided to signal or override the "deficient" status of a particular
+compiler.
+
+|Note:| |BOOST_MPL_HAS_XXX_TEMPLATE_DEF| is a simplified front end to
+the |BOOST_MPL_HAS_XXX_TEMPLATE_NAMED_DEF| introspection macro |-- end
+note|
+
+
+Header
+------
+
+.. parsed-literal::
+    
+    #include <boost/mpl/has_xxx.hpp>
+
+
+Parameters
+----------
+
+
++---------------+-------------------------------+---------------------------------------------------+
+| Parameter     | Requirement                   | Description                                       |
++===============+===============================+===================================================+
+| ``name``      | A legal identifier token      | A name of the template member being detected.     |
++---------------+-------------------------------+---------------------------------------------------+
+| ``n``         | An integral constant >= 0     | The arity of the template member being detected.  |
++---------------+-------------------------------+---------------------------------------------------+
+
+
+Expression semantics
+--------------------
+
+For any legal C++ identifier ``name`` and integral constant expression
+``n`` greater than or equal to 0:
+
+.. parsed-literal::
+
+    BOOST_MPL_HAS_XXX_TEMPLATE_DEF(name, n)
+
+:Precondition:
+    Appears at namespace scope.
+
+:Return type:
+    None.
+
+:Semantics:
+    Equivalent to
+
+    .. parsed-literal::
+
+        BOOST_MPL_HAS_XXX_TEMPLATE_NAMED_DEF(
+              BOOST_PP_CAT(has\_,name), name, n, false
+            )
+
+
+Example
+-------
+
+.. parsed-literal::
+    
+    BOOST_MPL_HAS_XXX_TEMPLATE_DEF(xxx, 1)
+    
+    struct test1  {};
+    struct test2  { void xxx(); };
+    struct test3  { int xxx; };
+    struct test4  { static int xxx(); };
+    struct test5  { typedef int xxx; };
+    struct test6  { struct xxx; };
+    struct test7  { typedef void (\*xxx)(); };
+    struct test8  { typedef void (xxx)(); };
+    struct test9  { template< class T > struct xxx {}; };
+    
+    BOOST_MPL_ASSERT_NOT(( has_xxx<test1, int> ));
+    BOOST_MPL_ASSERT_NOT(( has_xxx<test2, int> ));
+    BOOST_MPL_ASSERT_NOT(( has_xxx<test3, int> ));
+    BOOST_MPL_ASSERT_NOT(( has_xxx<test4, int> ));
+    BOOST_MPL_ASSERT_NOT(( has_xxx<test5, int> ));
+    BOOST_MPL_ASSERT_NOT(( has_xxx<test6, int> ));
+    BOOST_MPL_ASSERT_NOT(( has_xxx<test7, int> ));
+    BOOST_MPL_ASSERT_NOT(( has_xxx<test8, int> ));
+    
+    #if !defined(BOOST_MPL_CFG_NO_HAS_XXX_TEMPLATE)
+    BOOST_MPL_ASSERT(( has_xxx<test9, int> ));
+    #endif
+    
+    BOOST_MPL_ASSERT(( has_xxx<test9, int, true\_> ));
+
+
+See also
+--------
+
+|Macros|, |BOOST_MPL_HAS_XXX_TEMPLATE_NAMED_DEF|, |BOOST_MPL_CFG_NO_HAS_XXX_TEMPLATE|
+
Added: trunk/libs/mpl/doc/src/refmanual/HAS_XXX_TEMPLATE_NAMED_DEF.rst
==============================================================================
--- (empty file)
+++ trunk/libs/mpl/doc/src/refmanual/HAS_XXX_TEMPLATE_NAMED_DEF.rst	2010-06-08 10:24:55 EDT (Tue, 08 Jun 2010)
@@ -0,0 +1,170 @@
+.. Macros/Introspection//BOOST_MPL_HAS_XXX_TEMPLATE_NAMED_DEF
+
+.. Copyright Daniel Walker 2007.
+.. 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)
+
+BOOST_MPL_HAS_XXX_TEMPLATE_NAMED_DEF
+====================================
+
+Synopsis
+--------
+
+.. parsed-literal::
+
+    #define BOOST_MPL_HAS_XXX_TEMPLATE_NAMED_DEF(trait, name, n, default\_) \\
+        |unspecified-token-seq| \\
+    /\*\*/
+
+
+Description
+-----------
+
+Expands into the definition of a boolean n-ary |Metafunction| ``trait``
+such that for any types ``x, a1, a2, ..., an`` ``trait<x, a1, ...,
+an>::value == true`` if and only if ``x`` is a class type and has a
+nested template member ``x::template name<a1, ..., an>``.
+
+On deficient compilers not capable of performing the detection,
+``trait<x, a1, ..., an>::value`` always returns a fallback value
+``default_``.  A boolean configuration macro,
+|BOOST_MPL_CFG_NO_HAS_XXX_TEMPLATE|, is provided to signal or override
+the "deficient" status of a particular compiler.  |Note:| The fallback
+value can also be provided at the point of the metafunction
+invocation; see the `Expression semantics` section for details |-- end
+note|
+
+
+Header
+------
+
+.. parsed-literal::
+    
+    #include <boost/mpl/has_xxx.hpp>
+
+
+Parameters
+----------
+
++---------------+-------------------------------+---------------------------------------------------+
+| Parameter     | Requirement                   | Description                                       |
++===============+===============================+===================================================+
+| ``trait``     | A legal identifier token      | A name of the metafunction to be generated.       |
++---------------+-------------------------------+---------------------------------------------------+
+| ``name``      | A legal identifier token      | A name of the member being detected.              |
++---------------+-------------------------------+---------------------------------------------------+
+| ``n``         | An integral constant >= 0     | The arity of the template member being detected.  |
++---------------+-------------------------------+---------------------------------------------------+
+| ``default_``  | An boolean constant           | A fallback value for the deficient compilers.     |
++---------------+-------------------------------+---------------------------------------------------+
+
+
+Expression semantics
+--------------------
+
+For any legal C++ identifiers ``trait`` and ``name``, integral
+constant expression ``n`` greater than or equal to 0, boolean constant
+expression ``c1``, boolean |Integral Constant| ``c2``, and arbitrary
+type ``x``:
+
+.. parsed-literal::
+
+    BOOST_MPL_HAS_XXX_TEMPLATE_NAMED_DEF(trait, name, n, c1)
+
+:Precondition:
+    Appears at namespace scope.
+
+:Return type:
+    None.
+
+:Semantics:
+    Expands into an equivalent of the following class template
+    definition
+
+    .. parsed-literal::
+
+        template<
+            typename X
+          , typename A1, ..., typename An
+          , typename fallback = boost::mpl::bool\_<c1>
+        >
+        struct trait
+        {
+            // |unspecified|
+            // ...
+        };
+    
+    where ``trait`` is a boolean |Metafunction| with the following
+    semantics:
+    
+    .. parsed-literal::
+
+        typedef trait<x, a1, ..., an>::type r;
+
+    :Return type:
+        |Integral Constant|.
+
+    :Semantics:
+        If |BOOST_MPL_CFG_NO_HAS_XXX_TEMPLATE| is defined, ``r::value
+        == c1``; otherwise, ``r::value == true`` if and only if ``x``
+        is a class type that has a nested type member ``x::template
+        name<a1, ..., an>``.
+    
+    
+    .. parsed-literal::
+
+        typedef trait< x, a1, ..., an, c2 >::type r;
+
+    :Return type:
+        |Integral Constant|.
+
+    :Semantics:
+        If |BOOST_MPL_CFG_NO_HAS_XXX_TEMPLATE| is defined, ``r::value
+        == c2::value``; otherwise, equivalent to
+
+        .. parsed-literal::
+
+            typedef trait<x, a1, ..., an>::type r;
+
+
+Example
+-------
+
+.. parsed-literal::
+    
+    BOOST_MPL_HAS_XXX_TEMPLATE_NAMED_DEF(
+        has_xxx, xxx, 1, false
+    )
+
+    struct test1  {};
+    struct test2  { void xxx(); };
+    struct test3  { int xxx; };
+    struct test4  { static int xxx(); };
+    struct test5  { typedef int xxx; };
+    struct test6  { struct xxx; };
+    struct test7  { typedef void (\*xxx)(); };
+    struct test8  { typedef void (xxx)(); };
+    struct test9  { template< class T > struct xxx {}; };
+
+    BOOST_MPL_ASSERT_NOT(( has_xxx<test1, int> ));
+    BOOST_MPL_ASSERT_NOT(( has_xxx<test2, int> ));
+    BOOST_MPL_ASSERT_NOT(( has_xxx<test3, int> ));
+    BOOST_MPL_ASSERT_NOT(( has_xxx<test4, int> ));
+    BOOST_MPL_ASSERT_NOT(( has_xxx<test5, int> ));
+    BOOST_MPL_ASSERT_NOT(( has_xxx<test6, int> ));
+    BOOST_MPL_ASSERT_NOT(( has_xxx<test7, int> ));
+    BOOST_MPL_ASSERT_NOT(( has_xxx<test8, int> ));
+
+    #if !defined(BOOST_MPL_CFG_NO_HAS_XXX_TEMPLATE)
+    BOOST_MPL_ASSERT(( has_xxx<test9, int> ));
+    #endif
+
+    BOOST_MPL_ASSERT(( has_xxx<test9, int, true\_> ));
+
+
+See also
+--------
+
+|Macros|, |BOOST_MPL_HAS_XXX_TEMPLATE_DEF|, |BOOST_MPL_CFG_NO_HAS_XXX_TEMPLATE|
+
Modified: trunk/libs/mpl/test/has_xxx.cpp
==============================================================================
--- trunk/libs/mpl/test/has_xxx.cpp	(original)
+++ trunk/libs/mpl/test/has_xxx.cpp	2010-06-08 10:24:55 EDT (Tue, 08 Jun 2010)
@@ -1,5 +1,6 @@
 
 // Copyright Aleksey Gurtovoy 2000-2004
+// Copyright Daniel Walker 2007
 //
 // Distributed under the Boost Software License, Version 1.0. 
 // (See accompanying file LICENSE_1_0.txt or copy at 
@@ -16,6 +17,12 @@
 #include <boost/mpl/aux_/test.hpp>
 
 BOOST_MPL_HAS_XXX_TRAIT_DEF(xxx)
+BOOST_MPL_HAS_XXX_TEMPLATE_NAMED_DEF(has_xxx0, xxx, 0, false)
+BOOST_MPL_HAS_XXX_TEMPLATE_NAMED_DEF(has_xxx1, xxx, 1, false)
+BOOST_MPL_HAS_XXX_TEMPLATE_NAMED_DEF(has_xxx2, xxx, 2, false)
+BOOST_MPL_HAS_XXX_TEMPLATE_DEF(yyy0, 0)
+BOOST_MPL_HAS_XXX_TEMPLATE_DEF(yyy1, 1)
+BOOST_MPL_HAS_XXX_TEMPLATE_DEF(yyy2, 2)
 
 struct a1 {};
 struct a2 { void xxx(); };
@@ -31,6 +38,13 @@
 struct b6 { typedef void (*xxx)(); };
 struct b7 { typedef void (xxx)(); };
 
+struct c0 { template< typename T0 = int > struct xxx {}; };
+struct c1 { template< typename T1 > struct xxx {}; };
+struct c2 { template< typename T1, typename T2 > struct xxx {}; };
+struct c3 { template< typename T0 = int > struct yyy0 {}; };
+struct c4 { template< typename T1 > struct yyy1 {}; };
+struct c5 { template< typename T1, typename T2 > struct yyy2 {}; };
+
 template< typename T > struct outer;
 template< typename T > struct inner { typedef typename T::type type; };
 
@@ -42,25 +56,195 @@
 MPL_TEST_CASE()
 {
     MPL_ASSERT_NOT(( has_xxx<int> ));
+    MPL_ASSERT_NOT(( has_xxx0< int > ));
+    MPL_ASSERT_NOT(( has_xxx1< int, int > ));
+    MPL_ASSERT_NOT(( has_xxx2< int, int, int > ));
+    MPL_ASSERT_NOT(( has_yyy0< int > ));
+    MPL_ASSERT_NOT(( has_yyy1< int, int > ));
+    MPL_ASSERT_NOT(( has_yyy2< int, int, int > ));
+
 #if !BOOST_WORKAROUND(BOOST_MSVC, <= 1300)
     MPL_ASSERT_NOT(( has_xxx<int&> ));
+    MPL_ASSERT_NOT(( has_xxx0< int& > ));
+    MPL_ASSERT_NOT(( has_xxx1< int&, int > ));
+    MPL_ASSERT_NOT(( has_xxx2< int&, int, int > ));
+    MPL_ASSERT_NOT(( has_yyy0< int& > ));
+    MPL_ASSERT_NOT(( has_yyy1< int&, int > ));
+    MPL_ASSERT_NOT(( has_yyy2< int&, int, int > ));
+
     MPL_ASSERT_NOT(( has_xxx<int*> ));
+    MPL_ASSERT_NOT(( has_xxx0< int* > ));
+    MPL_ASSERT_NOT(( has_xxx1< int*, int > ));
+    MPL_ASSERT_NOT(( has_xxx2< int*, int, int > ));
+    MPL_ASSERT_NOT(( has_yyy0< int* > ));
+    MPL_ASSERT_NOT(( has_yyy1< int*, int > ));
+    MPL_ASSERT_NOT(( has_yyy2< int*, int, int > ));
+
     MPL_ASSERT_NOT(( has_xxx<int[]> ));
+    MPL_ASSERT_NOT(( has_xxx0< int[] > ));
+    MPL_ASSERT_NOT(( has_xxx1< int[], int > ));
+    MPL_ASSERT_NOT(( has_xxx2< int[], int, int > ));
+    MPL_ASSERT_NOT(( has_yyy0< int[] > ));
+    MPL_ASSERT_NOT(( has_yyy1< int[], int > ));
+    MPL_ASSERT_NOT(( has_yyy2< int[], int, int > ));
+
     MPL_ASSERT_NOT(( has_xxx<int (*)()> ));
+    MPL_ASSERT_NOT(( has_xxx0< int (*)() > ));
+    MPL_ASSERT_NOT(( has_xxx1< int (*)(), int > ));
+    MPL_ASSERT_NOT(( has_xxx2< int (*)(), int, int > ));
+    MPL_ASSERT_NOT(( has_yyy0< int (*)() > ));
+    MPL_ASSERT_NOT(( has_yyy1< int (*)(), int > ));
+    MPL_ASSERT_NOT(( has_yyy2< int (*)(), int, int > ));
 
     MPL_ASSERT_NOT(( has_xxx<a2> ));
+    MPL_ASSERT_NOT(( has_xxx0< a2 > ));
+    MPL_ASSERT_NOT(( has_xxx1< a2, int > ));
+    MPL_ASSERT_NOT(( has_xxx2< a2, int, int > ));
+    MPL_ASSERT_NOT(( has_yyy0< a2 > ));
+    MPL_ASSERT_NOT(( has_yyy1< a2, int > ));
+    MPL_ASSERT_NOT(( has_yyy2< a2, int, int > ));
+
     MPL_ASSERT_NOT(( has_xxx<a3> ));
+    MPL_ASSERT_NOT(( has_xxx0< a3 > ));
+    MPL_ASSERT_NOT(( has_xxx1< a3, int > ));
+    MPL_ASSERT_NOT(( has_xxx2< a3, int, int > ));
+    MPL_ASSERT_NOT(( has_yyy0< a3 > ));
+    MPL_ASSERT_NOT(( has_yyy1< a3, int > ));
+    MPL_ASSERT_NOT(( has_yyy2< a3, int, int > ));
+
     MPL_ASSERT_NOT(( has_xxx<a4> ));
+    MPL_ASSERT_NOT(( has_xxx0< a4 > ));
+    MPL_ASSERT_NOT(( has_xxx1< a4, int > ));
+    MPL_ASSERT_NOT(( has_xxx2< a4, int, int > ));
+    MPL_ASSERT_NOT(( has_yyy0< a4 > ));
+    MPL_ASSERT_NOT(( has_yyy1< a4, int > ));
+    MPL_ASSERT_NOT(( has_yyy2< a4, int, int > ));
+
 #if !BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3202))
     MPL_ASSERT_NOT(( has_xxx<a5> ));
 #endif
     MPL_ASSERT_NOT(( has_xxx< enum_ > ));
+    MPL_ASSERT_NOT(( has_xxx0< enum_ > ));
+    MPL_ASSERT_NOT(( has_xxx1< enum_, int > ));
+    MPL_ASSERT_NOT(( has_xxx2< enum_, int, int > ));
+    MPL_ASSERT_NOT(( has_yyy0< enum_ > ));
+    MPL_ASSERT_NOT(( has_yyy1< enum_, int > ));
+    MPL_ASSERT_NOT(( has_yyy2< enum_, int, int > ));
 #endif
+
     MPL_ASSERT_NOT(( has_xxx<a1> ));
+    MPL_ASSERT_NOT(( has_xxx0< a1 > ));
+    MPL_ASSERT_NOT(( has_xxx1< a1, int > ));
+    MPL_ASSERT_NOT(( has_xxx2< a1, int, int > ));
+    MPL_ASSERT_NOT(( has_yyy0< a1 > ));
+    MPL_ASSERT_NOT(( has_yyy1< a1, int > ));
+    MPL_ASSERT_NOT(( has_yyy2< a1, int, int > ));
+
     MPL_ASSERT_NOT(( has_xxx< outer< inner<int> > > ));
+    MPL_ASSERT_NOT(( has_xxx0< outer< inner<int> > > ));
+    MPL_ASSERT_NOT(( has_xxx1< outer< inner<int> >, int > ));
+    MPL_ASSERT_NOT(( has_xxx2< outer< inner<int> >, int, int > ));
+    MPL_ASSERT_NOT(( has_yyy0< outer< inner<int> > > ));
+    MPL_ASSERT_NOT(( has_yyy1< outer< inner<int> >, int > ));
+    MPL_ASSERT_NOT(( has_yyy2< outer< inner<int> >, int, int > ));
+
     MPL_ASSERT_NOT(( has_xxx< incomplete > ));
+    MPL_ASSERT_NOT(( has_xxx0< incomplete > ));
+    MPL_ASSERT_NOT(( has_xxx1< incomplete, int > ));
+    MPL_ASSERT_NOT(( has_xxx2< incomplete, int, int > ));
+    MPL_ASSERT_NOT(( has_yyy0< incomplete > ));
+    MPL_ASSERT_NOT(( has_yyy1< incomplete, int > ));
+    MPL_ASSERT_NOT(( has_yyy2< incomplete, int, int > ));
+
     MPL_ASSERT_NOT(( has_xxx< abstract > ));
+    MPL_ASSERT_NOT(( has_xxx0< abstract > ));
+    MPL_ASSERT_NOT(( has_xxx1< abstract, int > ));
+    MPL_ASSERT_NOT(( has_xxx2< abstract, int, int > ));
+    MPL_ASSERT_NOT(( has_yyy0< abstract > ));
+    MPL_ASSERT_NOT(( has_yyy1< abstract, int > ));
+    MPL_ASSERT_NOT(( has_yyy2< abstract, int, int > ));
+
     MPL_ASSERT_NOT(( has_xxx< noncopyable > ));
+    MPL_ASSERT_NOT(( has_xxx0< noncopyable > ));
+    MPL_ASSERT_NOT(( has_xxx1< noncopyable, int > ));
+    MPL_ASSERT_NOT(( has_xxx2< noncopyable, int, int > ));
+    MPL_ASSERT_NOT(( has_yyy0< noncopyable > ));
+    MPL_ASSERT_NOT(( has_yyy1< noncopyable, int > ));
+    MPL_ASSERT_NOT(( has_yyy2< noncopyable, int, int > ));
+
+#if !BOOST_WORKAROUND(__COMO_VERSION__, BOOST_TESTED_AT(4308))
+    MPL_ASSERT_NOT(( has_xxx0< b1 > ));
+    MPL_ASSERT_NOT(( has_xxx1< b1, int > ));
+    MPL_ASSERT_NOT(( has_xxx2< b1, int, int > ));
+    MPL_ASSERT_NOT(( has_yyy0< b1 > ));
+    MPL_ASSERT_NOT(( has_yyy1< b1, int > ));
+    MPL_ASSERT_NOT(( has_yyy2< b1, int, int > ));
+
+    MPL_ASSERT_NOT(( has_xxx0< b2 > ));
+    MPL_ASSERT_NOT(( has_xxx1< b2, int > ));
+    MPL_ASSERT_NOT(( has_xxx2< b2, int, int > ));
+    MPL_ASSERT_NOT(( has_yyy0< b2 > ));
+    MPL_ASSERT_NOT(( has_yyy1< b2, int > ));
+    MPL_ASSERT_NOT(( has_yyy2< b2, int, int > ));
+
+    MPL_ASSERT_NOT(( has_xxx0< b3 > ));
+    MPL_ASSERT_NOT(( has_xxx1< b3, int > ));
+    MPL_ASSERT_NOT(( has_xxx2< b3, int, int > ));
+    MPL_ASSERT_NOT(( has_yyy0< b3 > ));
+    MPL_ASSERT_NOT(( has_yyy1< b3, int > ));
+    MPL_ASSERT_NOT(( has_yyy2< b3, int, int > ));
+
+    MPL_ASSERT_NOT(( has_xxx0< b4 > ));
+    MPL_ASSERT_NOT(( has_xxx1< b4, int > ));
+    MPL_ASSERT_NOT(( has_xxx2< b4, int, int > ));
+    MPL_ASSERT_NOT(( has_yyy0< b4 > ));
+    MPL_ASSERT_NOT(( has_yyy1< b4, int > ));
+    MPL_ASSERT_NOT(( has_yyy2< b4, int, int > ));
+
+    MPL_ASSERT_NOT(( has_xxx0< b5 > ));
+    MPL_ASSERT_NOT(( has_xxx1< b5, int > ));
+    MPL_ASSERT_NOT(( has_xxx2< b5, int, int > ));
+    MPL_ASSERT_NOT(( has_yyy0< b5 > ));
+    MPL_ASSERT_NOT(( has_yyy1< b5, int > ));
+    MPL_ASSERT_NOT(( has_yyy2< b5, int, int > ));
+
+    MPL_ASSERT_NOT(( has_xxx0< b6 > ));
+    MPL_ASSERT_NOT(( has_xxx1< b6, int > ));
+    MPL_ASSERT_NOT(( has_xxx2< b6, int, int > ));
+    MPL_ASSERT_NOT(( has_yyy0< b6 > ));
+    MPL_ASSERT_NOT(( has_yyy1< b6, int > ));
+    MPL_ASSERT_NOT(( has_yyy2< b6, int, int > ));
+
+    MPL_ASSERT_NOT(( has_xxx0< b7 > ));
+    MPL_ASSERT_NOT(( has_xxx1< b7, int > ));
+    MPL_ASSERT_NOT(( has_xxx2< b7, int, int > ));
+    MPL_ASSERT_NOT(( has_yyy0< b7 > ));
+    MPL_ASSERT_NOT(( has_yyy1< b7, int > ));
+    MPL_ASSERT_NOT(( has_yyy2< b7, int, int > ));
+#endif
+
+    // Same name, different args.
+    //   Note: has_xxx0 is not test here because it's impossible to
+    //   declare a template with no arguments (only no required
+    //   arguments), so there is no zero argument substitute template
+    //   to reject n-ary member templates.
+#if (!BOOST_WORKAROUND(BOOST_MPL_CFG_GCC, <= 0x0303) \
+     && !BOOST_WORKAROUND(__COMO_VERSION__, BOOST_TESTED_AT(4308)))
+    MPL_ASSERT_NOT(( has_xxx1<c2, int> ));
+    MPL_ASSERT_NOT(( has_xxx2<c0, int, int> ));
+    MPL_ASSERT_NOT(( has_xxx2<c1, int, int> ));
+#endif
+
+    // Different name, same args.
+    MPL_ASSERT_NOT(( has_xxx0<c3> ));
+    MPL_ASSERT_NOT(( has_xxx1<c4, int> ));
+    MPL_ASSERT_NOT(( has_xxx2<c5, int, int> ));
+
+    // Different name, different args.
+    MPL_ASSERT_NOT(( has_xxx0<c4> ));
+    MPL_ASSERT_NOT(( has_xxx1<c5, int> ));
+    MPL_ASSERT_NOT(( has_xxx2<c3, int, int> ));
+    MPL_ASSERT_NOT(( has_xxx2<c4, int, int> ));
 
     MPL_ASSERT(( has_xxx<b1,true_> ));
     MPL_ASSERT(( has_xxx<b2,true_> ));
@@ -70,6 +254,15 @@
     MPL_ASSERT(( has_xxx<b6,true_> ));
     MPL_ASSERT(( has_xxx<b7,true_> ));
 
+#if !BOOST_WORKAROUND(__COMO_VERSION__, BOOST_TESTED_AT(4308)) && !BOOST_WORKAROUND(BOOST_MSVC, >= 1500)
+    MPL_ASSERT(( has_xxx0<c0, true_> ));
+    MPL_ASSERT(( has_yyy0<c3, true_> ));
+#endif
+    MPL_ASSERT(( has_xxx1<c1, int, true_> ));
+    MPL_ASSERT(( has_xxx2<c2, int, int, true_> ));
+    MPL_ASSERT(( has_yyy1<c4, int, true_> ));
+    MPL_ASSERT(( has_yyy2<c5, int, int, true_> ));
+
 #if !defined(HAS_XXX_ASSERT)
 #   define HAS_XXX_ASSERT(x) MPL_ASSERT(x)
 #endif
@@ -81,4 +274,17 @@
     HAS_XXX_ASSERT(( has_xxx<b5> ));
     HAS_XXX_ASSERT(( has_xxx<b6> ));
     HAS_XXX_ASSERT(( has_xxx<b7> ));
+
+#if !defined(HAS_XXX_TEMPLATE_ASSERT)
+#   define HAS_XXX_TEMPLATE_ASSERT(x) MPL_ASSERT(x)
+#endif
+
+#if !BOOST_WORKAROUND(__COMO_VERSION__, BOOST_TESTED_AT(4308)) && !BOOST_WORKAROUND(BOOST_MSVC, >= 1500)
+    HAS_XXX_TEMPLATE_ASSERT(( has_xxx0<c0> ));
+    HAS_XXX_TEMPLATE_ASSERT(( has_yyy0<c3> ));
+#endif
+    HAS_XXX_TEMPLATE_ASSERT(( has_xxx1<c1, int> ));
+    HAS_XXX_TEMPLATE_ASSERT(( has_xxx2<c2, int, int> ));
+    HAS_XXX_TEMPLATE_ASSERT(( has_yyy1<c4, int> ));
+    HAS_XXX_TEMPLATE_ASSERT(( has_yyy2<c5, int, int> ));
 }
Modified: trunk/libs/mpl/test/no_has_xxx.cpp
==============================================================================
--- trunk/libs/mpl/test/no_has_xxx.cpp	(original)
+++ trunk/libs/mpl/test/no_has_xxx.cpp	2010-06-08 10:24:55 EDT (Tue, 08 Jun 2010)
@@ -23,4 +23,8 @@
 #   define HAS_XXX_ASSERT(x) MPL_ASSERT_NOT(x)
 #endif
 
+#if defined(BOOST_MPL_CFG_NO_HAS_XXX_TEMPLATE)
+#   define HAS_XXX_TEMPLATE_ASSERT(x) MPL_ASSERT_NOT(x)
+#endif
+
 #include "has_xxx.cpp"