// Copyright David Abrahams, Daniel Wallin 2003. Use, modification and // distribution is subject to 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) #ifndef BOOST_NAMED_PARAMS_031014_HPP #define BOOST_NAMED_PARAMS_031014_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef BOOST_NAMED_PARAMS_MAX_ARITY # define BOOST_NAMED_PARAMS_MAX_ARITY 10 #endif #if defined(__GNUC__) && __GNUC__ < 3 # define BOOST_NAMED_PARAMS_GCC2 1 #else # define BOOST_NAMED_PARAMS_GCC2 0 #endif namespace boost { template class reference_wrapper; template struct keyword; template > struct named_param; namespace detail { // We have to build a conversion operator to get around ETI with // default function arguments; int seemed a little too easily // confused, so we'll use this special type instead. struct non_int_eti_type { private: non_int_eti_type(); }; typedef char yes_t; struct no_t { char x[128]; }; yes_t to_yesno(mpl::true_); no_t to_yesno(mpl::false_); template struct named_default { named_default(Default& x) : default_(x) {} Default& default_; }; #if BOOST_WORKAROUND(__EDG_VERSION__, <= 300) // These compilers need a little extra help with overload // resolution; we have nil's operator[] accept a base class to make // that overload less preferable. template struct lazy_named_default_base { lazy_named_default_base(const DefaultFn& x) : default_(x) {} const DefaultFn& default_; }; template struct lazy_named_default : lazy_named_default_base { lazy_named_default(const DefaultFn& x) : lazy_named_default_base(x) {} }; #else template struct lazy_named_default { lazy_named_default(const DefaultFn& x) : default_(x) {} const DefaultFn& default_; }; #endif template struct named; struct nil { nil() {} nil(BOOST_PP_ENUM_PARAMS( BOOST_NAMED_PARAMS_MAX_ARITY, nil BOOST_PP_INTERCEPT )) {} #if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) || BOOST_NAMED_PARAMS_GCC2 // A metafunction class which, given a keyword, returns the base // sublist whose get() function can produce the value for that // key. struct key_owner { template struct apply { typedef nil type; }; }; // A metafunction class which, given a keyword and a default // type, returns the appropriate result type for a keyword // lookup given that default struct key_value_type { template struct apply { typedef Default type; }; }; template Default& get(const named_default& x) const { return x.default_; } template typename Default::result_type get( const lazy_named_default& x) const { return x.default_(); } template Default& operator[](const named_default& x) const { return x.default_; } template typename Default::result_type operator[]( const lazy_named_default& x) const { return x.default_(); } #else template Default& operator[](const named_default& x) const { return x.default_; } # if BOOST_WORKAROUND(__EDG_VERSION__, <= 300) template typename Default::result_type operator[]( const lazy_named_default_base& x) const { return x.default_(); } # else template typename Default::result_type operator[]( const lazy_named_default& x) const { return x.default_(); } # endif #endif // No keyword was found if we get here, so we should only return // mpl::true_ if it's OK to have a default for the argument. template static typename Arg::has_default keyword_passes_predicate(Arg*); typedef mpl::true_ has_default; typedef mpl::always predicate; }; template struct key_value_type_mfn { typedef typename T::key_value_type type; }; // A tuple of labeled argument holders // Restructured this so that head isn't inherited // We'll need a version without using declarations for vc6/7.0 template struct list : T { typedef list self_t; typedef H head_type; typedef T tail_type; #if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) || BOOST_NAMED_PARAMS_GCC2 // A metafunction class which, given a keyword, returns the base // sublist whose get() function can produce the value for that // key. struct key_owner { template struct apply : mpl::eval_if< boost::is_same , mpl::identity , mpl::apply1 > {}; }; // A metafunction class which, given a keyword and a default // type, returns the appropriate result type for a keyword // lookup given that default struct key_value_type { template struct apply : mpl::eval_if< boost::is_same , mpl::identity , mpl::apply2 > { }; }; #endif H head; list() {} template< BOOST_PP_ENUM_PARAMS(BOOST_NAMED_PARAMS_MAX_ARITY, class A) > list( BOOST_PP_ENUM_BINARY_PARAMS(BOOST_NAMED_PARAMS_MAX_ARITY, A, const & a) ) : T(BOOST_PP_ENUM_SHIFTED_PARAMS(BOOST_NAMED_PARAMS_MAX_ARITY, a), nil()) , head(a0) {} list(H const& head_, T const& tail) : T(tail) , head(head_) { } #if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) || BOOST_NAMED_PARAMS_GCC2 template typename mpl::apply2::type& operator[](const keyword& x) const { typename mpl::apply1::type const& sublist = *this; return sublist.get(x); } template typename mpl::apply2::type& operator[](const named_default& x) const { typename mpl::apply1::type const& sublist = *this; return sublist.get(x); } template typename mpl::apply2< key_value_type,KW , typename Default::result_type >::type operator[](const lazy_named_default& x) const { typename mpl::apply1::type const& sublist = *this; return sublist.get(x); } typename H::value_type& get(const keyword& x) const { return head[x]; } template typename H::value_type& get( const named_default& x) const { return head[x]; } template typename H::value_type& get( const lazy_named_default& x) const { return head[x]; } #else typename H::value_type& operator[](const keyword& x) const { return head[x]; } template typename H::value_type& operator[](const named_default& x) const { return head[x]; } template typename H::value_type& operator[](const lazy_named_default& x) const { return head[x]; } using T::operator[]; template static typename mpl::apply1< typename mpl::lambda::type , typename H::value_type >::type keyword_passes_predicate(named_param*); using T::keyword_passes_predicate; #endif template list, self_t> operator,(named const& x) const { return list, self_t>( x, *this ); } }; template <> struct list {}; template struct named { typedef KW key_type; typedef T value_type; named(T& x) : val(x) {} T& operator[](const keyword&) const { return val; } template T& operator[](const named_default&) const { return val; } template T& operator[](const lazy_named_default&) const { return val; } template list, list > > operator,(named const& x) const { return list, list > >( *this, list >(x, nil()) ); } T& val; }; BOOST_PYTHON_IS_XXX_DEF(named,named,2) template yes_t is_const_reference_wrapper_check(const reference_wrapper*); no_t is_const_reference_wrapper_check(...); // Returns mpl::true_ if T is of type const reference_wrapper template struct is_const_reference_wrapper { BOOST_STATIC_CONSTANT( bool, value = ( sizeof(is_const_reference_wrapper_check((T*)0)) == sizeof(yes_t) ) ); typedef mpl::bool_ type; }; template struct get_type { typedef typename T::type type; }; // Produces the unwrapped type to hold a reference to in named<> // Can't use boost::unwrap_reference<> here because it // doesn't handle the case where T = const reference_wrapper template struct unwrap_cv_reference { typedef typename mpl::eval_if< is_const_reference_wrapper , get_type , mpl::identity >::type type; }; } // namespace detail template struct keyword { #if !BOOST_WORKAROUND(BOOST_MSVC, == 1200) // partial ordering bug template detail::named::type> operator=(T const& x) const { return detail::named::type>(x); } #endif template detail::named::type> operator=(T& x) const { return detail::named::type>(x); } template detail::named operator()(T& x) const { return detail::named(x); } #if !BOOST_WORKAROUND(BOOST_MSVC, == 1200) // partial ordering bug template detail::named operator()(T const& x) const { return detail::named(x); } #endif template detail::named_default operator|(Default& default_) const { return detail::named_default(default_); } #if !BOOST_WORKAROUND(BOOST_MSVC, == 1200) // partial ordering bug template detail::named_default operator|(const Default& default_) const { return detail::named_default(default_); } #endif template detail::lazy_named_default operator||(const Default& default_) const { return detail::lazy_named_default(default_); } }; template struct named_param { typedef Tag key_type; typedef HasDefault has_default; typedef Predicate predicate; }; namespace detail { BOOST_PYTHON_IS_XXX_DEF(named_param,named_param,3) template struct get_key_type { typedef typename T::key_type type; }; template struct key_type : mpl::eval_if< is_named_param , get_key_type , mpl::identity > { }; template struct get_has_default { typedef typename T::has_default type; }; template struct has_default : mpl::eval_if< is_named_param , get_has_default , mpl::true_ > { }; template struct get_predicate { typedef typename T::predicate type; }; template struct predicate : mpl::eval_if< is_named_param , get_predicate , mpl::identity > > { }; template struct as_arg { typedef named_param< typename key_type::type , typename has_default::type , typename predicate::type > type; }; // labels T with keyword KW if it is not already named template struct as_named { typedef typename mpl::if_< is_named , T , named::type, typename unwrap_cv_reference::type> >::type type; }; #if BOOST_WORKAROUND(BOOST_MSVC, == 1200) template <> struct as_named { typedef int type; }; #endif // Seq ::= a list of named objects // Arg ::= an arg<...> instantiation // // if (named in Seq) // return Arg::predicate::type // else // return Arg::has_default template struct keyword_passes_predicate_aux { BOOST_STATIC_CONSTANT( bool, value = ( sizeof( to_yesno( Seq::keyword_passes_predicate((Arg*)0) )) == sizeof(yes_t) ) ); typedef mpl::bool_ type; }; template struct keyword_passes_predicate : keyword_passes_predicate_aux::type> {}; template struct restrict_keywords { template struct apply { struct type_ : Keywords { type_(const Keywords&) {} }; typedef type_ type; }; }; #if BOOST_WORKAROUND(BOOST_MSVC, == 1200) // ETI workaround template <> struct restrict_keywords { template struct apply { typedef int type; }; }; #endif template <> struct restrict_keywords { template struct apply {}; }; // Given actual argument types T0...Tn, return a list of // named types where: // // T0...Tm != nil // // and // // Ui = Ti is named<...> ? Ti : named // template< BOOST_PP_ENUM_BINARY_PARAMS( BOOST_NAMED_PARAMS_MAX_ARITY, class T, = nil BOOST_PP_INTERCEPT ) > struct make_named_list { template< BOOST_PP_ENUM_PARAMS(BOOST_NAMED_PARAMS_MAX_ARITY, class K) > struct apply { typedef list< typename as_named::type // Had to use nested template invocation directly // instead of mpl::apply<> because // BOOST_NAMED_PARAMS_MAX_ARITY > BOOST_MPL_LIMIT_METAFUNCTION_ARITY , typename make_named_list< BOOST_PP_ENUM_SHIFTED_PARAMS(BOOST_NAMED_PARAMS_MAX_ARITY, T) , nil >::BOOST_NESTED_TEMPLATE apply< BOOST_PP_ENUM_SHIFTED_PARAMS(BOOST_NAMED_PARAMS_MAX_ARITY, K) , nil >::type > type; }; }; template <> struct make_named_list< BOOST_PP_ENUM_PARAMS(BOOST_NAMED_PARAMS_MAX_ARITY, nil BOOST_PP_INTERCEPT) > { template< BOOST_PP_ENUM_PARAMS(BOOST_NAMED_PARAMS_MAX_ARITY, class K) > struct apply { typedef nil type; }; }; } // namespace detail #define BOOST_KEYWORDS_TEMPLATE_ARGS(z, n, text) class BOOST_PP_CAT(K, n) = detail::nil template< class K0 , BOOST_PP_ENUM_SHIFTED(BOOST_NAMED_PARAMS_MAX_ARITY, BOOST_KEYWORDS_TEMPLATE_ARGS, _) > struct keywords { #undef BOOST_KEYWORDS_TEMPLATE_ARGS typedef keywords< BOOST_PP_ENUM_PARAMS(BOOST_NAMED_PARAMS_MAX_ARITY, K) > self_t; #ifndef BOOST_NO_SFINAE // if the elements of NamedList match the criteria of overload // resolution, returns a type which can be constructed from // self_t. Otherwise, this is not a valid metafunction (no nested // ::type). // Had to switch from mpl::and_ to mpl::and_ > // because BOOST_NAMED_PARAMS_MAX_ARITY > BOOST_MPL_LIMIT_METAFUNCTION_ARITY # define BOOST_PASSES_PREDICATE_LHS(z, n, text) \ mpl::and_< /**/ # define BOOST_PASSES_PREDICATE_RHS(z, n, text) \ , detail::keyword_passes_predicate > /**/ template struct restrict_base { // metafunction forwarding here would confuse vc6 typedef mpl::apply1< detail::restrict_keywords< typename BOOST_PP_REPEAT( BOOST_PP_DEC(BOOST_NAMED_PARAMS_MAX_ARITY) , BOOST_PASSES_PREDICATE_LHS , _ ) detail::keyword_passes_predicate BOOST_PP_REPEAT( BOOST_PP_DEC(BOOST_NAMED_PARAMS_MAX_ARITY) , BOOST_PASSES_PREDICATE_RHS , _ )::type > , self_t > type; }; # undef BOOST_PASSES_PREDICATE_LHS # undef BOOST_PASSES_PREDICATE_RHS #endif // Instantiations are to be used as an optional argument to control SFINAE template< BOOST_PP_ENUM_BINARY_PARAMS( BOOST_NAMED_PARAMS_MAX_ARITY, class T, = detail::nil BOOST_PP_INTERCEPT ) > struct restrict #ifndef BOOST_NO_SFINAE : restrict_base< // Build a list of named items for each keyword and actual type // Had to use nested template invocation directly // instead of mpl::apply<> because // BOOST_NAMED_PARAMS_MAX_ARITY > BOOST_MPL_LIMIT_METAFUNCTION_ARITY BOOST_DEDUCED_TYPENAME detail::make_named_list< BOOST_PP_ENUM_PARAMS(BOOST_NAMED_PARAMS_MAX_ARITY, T) >::BOOST_NESTED_TEMPLATE apply< BOOST_PP_ENUM_PARAMS(BOOST_NAMED_PARAMS_MAX_ARITY, K) >::type >::type #endif { #ifdef BOOST_NO_SFINAE typedef self_t type; #endif }; detail::nil operator()() const { return detail::nil(); } #define BOOST_PP_ITERATION_PARAMS_1 (3,( \ 1,BOOST_NAMED_PARAMS_MAX_ARITY, \ )) #include BOOST_PP_ITERATE() }; namespace detail { // This metafunction class extracts the actual type of the argument passed // to a specified keyword object given type KW; recursively goes through // through each nested list<...> as it attempts to find a match. template< typename Params > struct named_param_value_type { template< typename KW, typename Default > struct apply { typedef typename Params::head_type head_type; typedef typename Params::tail_type tail_type; typedef typename head_type::key_type key_type; typedef typename head_type::value_type value_type; typedef typename mpl::eval_if< is_same , mpl::identity , mpl::apply2< named_param_value_type , KW , Default > >::type type; }; }; // If no keyword object has been specified, // this metafunction returns typename Default::type. // This facilitates conditional type evaluation of Default. template<> struct named_param_value_type { template< typename KW, typename Default > struct apply { typedef typename Default::type type; }; }; } // namespace detail template< typename Params, typename KW, typename Default = detail::no_t > struct find_named_param { typedef typename mpl::apply2< detail::named_param_value_type , KW , Default >::type type; }; } // namespace boost #undef BOOST_NAMED_PARAMS_GCC2 #include #include #include #include #include #include #define BOOST_NAMED_PARAMS_FUN_TEMPLATE_HEAD1(n) \ template #define BOOST_NAMED_PARAMS_FUN_TEMPLATE_HEAD0(n) #define BOOST_NAMED_PARAMS_FUN_DECL(z, n, params) \ BOOST_PP_CAT(BOOST_NAMED_PARAMS_FUN_TEMPLATE_HEAD, BOOST_PP_BOOL(n))(n) \ BOOST_PP_TUPLE_ELEM(3, 0, params) \ BOOST_PP_TUPLE_ELEM(3, 1, params)( \ BOOST_PP_ENUM_BINARY_PARAMS(n, const T, &p) \ BOOST_PP_COMMA_IF(n) \ BOOST_PP_EXPR_IF(n, typename) BOOST_PP_TUPLE_ELEM(3, 2, params)::restrict \ <\ BOOST_PP_ENUM_PARAMS(n, T)\ >::type kw = BOOST_PP_TUPLE_ELEM(3, 2, params)()\ ) \ { \ return BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(3, 1, params), _with_named_params)( \ kw(BOOST_PP_ENUM_PARAMS(n, p)) \ ); \ } #define BOOST_NAMED_PARAMS_FUN(ret, name, lo, hi, keywords) \ template \ ret BOOST_PP_CAT(name, _with_named_params)(const Params&);\ BOOST_PP_REPEAT_FROM_TO(lo, BOOST_PP_INC(hi), BOOST_NAMED_PARAMS_FUN_DECL, (ret, name, keywords)) \ template \ ret BOOST_PP_CAT(name, _with_named_params)(const Params& p) #include #endif // BOOST_NAMED_PARAMS_031014_HPP