1 // Copyright Daniel Wallin, David Abrahams 2005. Use, modification and 2 // distribution is subject to the Boost Software License, Version 1.0. (See 3 // accompanying file LICENSE_1_0.txt or copy at 4 // http://www.boost.org/LICENSE_1_0.txt) 5 6 #ifndef ARG_LIST_050329_HPP 7 #define ARG_LIST_050329_HPP 8 9 #include <boost/parameter/aux_/void.hpp> 10 #include <boost/parameter/aux_/result_of0.hpp> 11 #include <boost/parameter/aux_/default.hpp> 12 #include <boost/parameter/aux_/parameter_requirements.hpp> 13 #include <boost/parameter/aux_/yesno.hpp> 14 #include <boost/parameter/aux_/is_maybe.hpp> 15 #include <boost/parameter/config.hpp> 16 17 #include <boost/mpl/apply.hpp> 18 #include <boost/mpl/assert.hpp> 19 #include <boost/mpl/begin.hpp> 20 #include <boost/mpl/end.hpp> 21 #include <boost/mpl/iterator_tags.hpp> 22 23 #include <boost/type_traits/add_reference.hpp> 24 #include <boost/type_traits/is_same.hpp> 25 #include <boost/preprocessor/repetition/enum_params.hpp> 26 #include <boost/preprocessor/repetition/enum_binary_params.hpp> 27 #include <boost/preprocessor/facilities/intercept.hpp> 28 29 namespace boost { namespace parameter { 30 31 // Forward declaration for aux::arg_list, below. 32 template<class T> struct keyword; 33 34 namespace aux { 35 36 // Tag type passed to MPL lambda. 37 struct lambda_tag; 38 39 // 40 // Structures used to build the tuple of actual arguments. The 41 // tuple is a nested cons-style list of arg_list specializations 42 // terminated by an empty_arg_list. 43 // 44 // Each specialization of arg_list is derived from its successor in 45 // the list type. This feature is used along with using 46 // declarations to build member function overload sets that can 47 // match against keywords. 48 // 49 50 // MPL sequence support 51 struct arg_list_tag; 52 53 // Terminates arg_list<> and represents an empty list. Since this 54 // is just the terminating case you might want to look at arg_list 55 // first, to get a feel for what's really happening here. 56 57 struct empty_arg_list 58 { empty_arg_listboost::parameter::aux::empty_arg_list59 empty_arg_list() {} 60 61 // Constructor taking BOOST_PARAMETER_MAX_ARITY empty_arg_list 62 // arguments; this makes initialization empty_arg_listboost::parameter::aux::empty_arg_list63 empty_arg_list( 64 BOOST_PP_ENUM_PARAMS( 65 BOOST_PARAMETER_MAX_ARITY, void_ BOOST_PP_INTERCEPT 66 )) 67 {} 68 69 // A metafunction class that, given a keyword and a default 70 // type, returns the appropriate result type for a keyword 71 // lookup given that default 72 struct binding 73 { 74 template<class KW, class Default, class Reference> 75 struct apply 76 { 77 typedef Default type; 78 }; 79 }; 80 81 // Terminator for has_key, indicating that the keyword is unique 82 template <class KW> 83 static no_tag has_key(KW*); 84 85 #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) 86 87 // The overload set technique doesn't work with these older 88 // compilers, so they need some explicit handholding. 89 90 // A metafunction class that, given a keyword, returns the type 91 // of the base sublist whose get() function can produce the 92 // value for that key 93 struct key_owner 94 { 95 template<class KW> 96 struct apply 97 { 98 typedef empty_arg_list type; 99 }; 100 }; 101 102 template <class K, class T> getboost::parameter::aux::empty_arg_list103 T& get(default_<K,T> x) const 104 { 105 return x.value; 106 } 107 108 template <class K, class F> 109 typename result_of0<F>::type getboost::parameter::aux::empty_arg_list110 get(lazy_default<K,F> x) const 111 { 112 return x.compute_default(); 113 } 114 #endif 115 116 // If this function is called, it means there is no argument 117 // in the list that matches the supplied keyword. Just return 118 // the default value. 119 template <class K, class Default> operator []boost::parameter::aux::empty_arg_list120 Default& operator[](default_<K, Default> x) const 121 { 122 return x.value; 123 } 124 125 // If this function is called, it means there is no argument 126 // in the list that matches the supplied keyword. Just evaluate 127 // and return the default value. 128 template <class K, class F> 129 typename result_of0<F>::type operator []boost::parameter::aux::empty_arg_list130 operator[]( 131 BOOST_PARAMETER_lazy_default_fallback<K,F> x) const 132 { 133 return x.compute_default(); 134 } 135 136 // No argument corresponding to ParameterRequirements::key_type 137 // was found if we match this overload, so unless that parameter 138 // has a default, we indicate that the actual arguments don't 139 // match the function's requirements. 140 template <class ParameterRequirements, class ArgPack> 141 static typename ParameterRequirements::has_default 142 satisfies(ParameterRequirements*, ArgPack*); 143 144 // MPL sequence support 145 typedef empty_arg_list type; // convenience 146 typedef arg_list_tag tag; // For dispatching to sequence intrinsics 147 }; 148 149 // Forward declaration for arg_list::operator, 150 template <class KW, class T> 151 struct tagged_argument; 152 153 template <class T> 154 struct get_reference 155 { 156 typedef typename T::reference type; 157 }; 158 159 // A tuple of tagged arguments, terminated with empty_arg_list. 160 // Every TaggedArg is an instance of tagged_argument<>. 161 template <class TaggedArg, class Next = empty_arg_list> 162 struct arg_list : Next 163 { 164 typedef arg_list<TaggedArg,Next> self; 165 typedef typename TaggedArg::key_type key_type; 166 167 typedef typename is_maybe<typename TaggedArg::value_type>::type holds_maybe; 168 169 typedef typename mpl::eval_if< 170 holds_maybe 171 , get_reference<typename TaggedArg::value_type> 172 , get_reference<TaggedArg> 173 >::type reference; 174 175 typedef typename mpl::if_< 176 holds_maybe 177 , reference 178 , typename TaggedArg::value_type 179 >::type value_type; 180 181 TaggedArg arg; // Stores the argument 182 183 // Store the arguments in successive nodes of this list 184 template< // class A0, class A1, ... 185 BOOST_PP_ENUM_PARAMS(BOOST_PARAMETER_MAX_ARITY, class A) 186 > arg_listboost::parameter::aux::arg_list187 arg_list( // A0& a0, A1& a1, ... 188 BOOST_PP_ENUM_BINARY_PARAMS(BOOST_PARAMETER_MAX_ARITY, A, & a) 189 ) 190 : Next( // a1, a2, ... 191 BOOST_PP_ENUM_SHIFTED_PARAMS(BOOST_PARAMETER_MAX_ARITY, a) 192 , void_reference() 193 ) 194 , arg(a0) 195 {} 196 197 // Create a new list by prepending arg to a copy of tail. Used 198 // when incrementally building this structure with the comma 199 // operator. arg_listboost::parameter::aux::arg_list200 arg_list(TaggedArg head, Next const& tail) 201 : Next(tail) 202 , arg(head) 203 {} 204 205 // A metafunction class that, given a keyword and a default 206 // type, returns the appropriate result type for a keyword 207 // lookup given that default 208 struct binding 209 { 210 template <class KW, class Default, class Reference> 211 struct apply 212 { 213 typedef typename mpl::eval_if< 214 boost::is_same<KW, key_type> 215 , mpl::if_<Reference, reference, value_type> 216 , mpl::apply_wrap3<typename Next::binding, KW, Default, Reference> 217 >::type type; 218 }; 219 }; 220 221 #if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) 222 // Overload for key_type, so the assert below will fire if the 223 // same keyword is used again 224 static yes_tag has_key(key_type*); 225 using Next::has_key; 226 227 BOOST_MPL_ASSERT_MSG( 228 sizeof(Next::has_key((key_type*)0)) == sizeof(no_tag) 229 , duplicate_keyword, (key_type) 230 ); 231 232 #endif 233 // 234 // Begin implementation of indexing operators for looking up 235 // specific arguments by name 236 // 237 238 // Helpers that handle the case when TaggedArg is 239 // empty<T>. 240 template <class D> get_defaultboost::parameter::aux::arg_list241 reference get_default(D const&, mpl::false_) const 242 { 243 return arg.value; 244 } 245 246 template <class D> get_defaultboost::parameter::aux::arg_list247 reference get_default(D const& d, mpl::true_) const 248 { 249 return arg.value ? arg.value.get() : arg.value.construct(d.value); 250 } 251 252 #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) 253 // These older compilers don't support the overload set creation 254 // idiom well, so we need to do all the return type calculation 255 // for the compiler and dispatch through an outer function template 256 257 // A metafunction class that, given a keyword, returns the base 258 // sublist whose get() function can produce the value for that 259 // key. 260 struct key_owner 261 { 262 template<class KW> 263 struct apply 264 { 265 typedef typename mpl::eval_if< 266 boost::is_same<KW, key_type> 267 , mpl::identity<arg_list<TaggedArg,Next> > 268 , mpl::apply_wrap1<typename Next::key_owner,KW> 269 >::type type; 270 }; 271 }; 272 273 // Outer indexing operators that dispatch to the right node's 274 // get() function. 275 template <class KW> 276 typename mpl::apply_wrap3<binding, KW, void_, mpl::true_>::type operator []boost::parameter::aux::arg_list277 operator[](keyword<KW> const& x) const 278 { 279 typename mpl::apply_wrap1<key_owner, KW>::type const& sublist = *this; 280 return sublist.get(x); 281 } 282 283 template <class KW, class Default> 284 typename mpl::apply_wrap3<binding, KW, Default&, mpl::true_>::type operator []boost::parameter::aux::arg_list285 operator[](default_<KW, Default> x) const 286 { 287 typename mpl::apply_wrap1<key_owner, KW>::type const& sublist = *this; 288 return sublist.get(x); 289 } 290 291 template <class KW, class F> 292 typename mpl::apply_wrap3< 293 binding,KW 294 , typename result_of0<F>::type 295 , mpl::true_ 296 >::type operator []boost::parameter::aux::arg_list297 operator[](lazy_default<KW,F> x) const 298 { 299 typename mpl::apply_wrap1<key_owner, KW>::type const& sublist = *this; 300 return sublist.get(x); 301 } 302 303 // These just return the stored value; when empty_arg_list is 304 // reached, indicating no matching argument was passed, the 305 // default is returned, or if no default_ or lazy_default was 306 // passed, compilation fails. getboost::parameter::aux::arg_list307 reference get(keyword<key_type> const&) const 308 { 309 BOOST_MPL_ASSERT_NOT((holds_maybe)); 310 return arg.value; 311 } 312 313 template <class Default> getboost::parameter::aux::arg_list314 reference get(default_<key_type,Default> const& d) const 315 { 316 return get_default(d, holds_maybe()); 317 } 318 319 template <class Default> getboost::parameter::aux::arg_list320 reference get(lazy_default<key_type, Default>) const 321 { 322 return arg.value; 323 } 324 325 #else 326 operator []boost::parameter::aux::arg_list327 reference operator[](keyword<key_type> const&) const 328 { 329 BOOST_MPL_ASSERT_NOT((holds_maybe)); 330 return arg.value; 331 } 332 333 template <class Default> operator []boost::parameter::aux::arg_list334 reference operator[](default_<key_type, Default> const& d) const 335 { 336 return get_default(d, holds_maybe()); 337 } 338 339 template <class Default> operator []boost::parameter::aux::arg_list340 reference operator[](lazy_default<key_type, Default>) const 341 { 342 BOOST_MPL_ASSERT_NOT((holds_maybe)); 343 return arg.value; 344 } 345 346 // Builds an overload set including operator[]s defined in base 347 // classes. 348 using Next::operator[]; 349 350 // 351 // End of indexing support 352 // 353 354 355 // 356 // For parameter_requirements matching this node's key_type, 357 // return a bool constant wrapper indicating whether the 358 // requirements are satisfied by TaggedArg. Used only for 359 // compile-time computation and never really called, so a 360 // declaration is enough. 361 // 362 template <class HasDefault, class Predicate, class ArgPack> 363 static typename mpl::apply_wrap2< 364 typename mpl::lambda<Predicate, lambda_tag>::type 365 , value_type, ArgPack 366 >::type 367 satisfies( 368 parameter_requirements<key_type,Predicate,HasDefault>* 369 , ArgPack* 370 ); 371 372 // Builds an overload set including satisfies functions defined 373 // in base classes. 374 using Next::satisfies; 375 #endif 376 377 // Comma operator to compose argument list without using parameters<>. 378 // Useful for argument lists with undetermined length. 379 template <class KW, class T2> 380 arg_list<tagged_argument<KW, T2>, self> operator ,boost::parameter::aux::arg_list381 operator,(tagged_argument<KW,T2> x) const 382 { 383 return arg_list<tagged_argument<KW,T2>, self>(x, *this); 384 } 385 386 // MPL sequence support 387 typedef self type; // Convenience for users 388 typedef Next tail_type; // For the benefit of iterators 389 typedef arg_list_tag tag; // For dispatching to sequence intrinsics 390 }; 391 392 // MPL sequence support 393 template <class ArgumentPack> 394 struct arg_list_iterator 395 { 396 typedef mpl::forward_iterator_tag category; 397 398 // The incremented iterator 399 typedef arg_list_iterator<typename ArgumentPack::tail_type> next; 400 401 // dereferencing yields the key type 402 typedef typename ArgumentPack::key_type type; 403 }; 404 405 template <> 406 struct arg_list_iterator<empty_arg_list> {}; 407 408 }} // namespace parameter::aux 409 410 // MPL sequence support 411 namespace mpl 412 { 413 template <> 414 struct begin_impl<parameter::aux::arg_list_tag> 415 { 416 template <class S> 417 struct apply 418 { 419 typedef parameter::aux::arg_list_iterator<S> type; 420 }; 421 }; 422 423 template <> 424 struct end_impl<parameter::aux::arg_list_tag> 425 { 426 template <class> 427 struct apply 428 { 429 typedef parameter::aux::arg_list_iterator<parameter::aux::empty_arg_list> type; 430 }; 431 }; 432 } 433 434 } // namespace boost 435 436 #endif // ARG_LIST_050329_HPP 437 438