1 /*! 2 @file 3 Forward declares `boost::hana::type` and related utilities. 4 5 @copyright Louis Dionne 2013-2017 6 Distributed under the Boost Software License, Version 1.0. 7 (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 8 */ 9 10 #ifndef BOOST_HANA_FWD_TYPE_HPP 11 #define BOOST_HANA_FWD_TYPE_HPP 12 13 #include <boost/hana/config.hpp> 14 #include <boost/hana/fwd/core/make.hpp> 15 16 17 BOOST_HANA_NAMESPACE_BEGIN 18 //! Base class of `hana::type`; used for pattern-matching. 19 //! @relates hana::type 20 //! 21 //! Example 22 //! ------- 23 //! @include example/type/basic_type.cpp 24 template <typename T> 25 struct basic_type; 26 27 //! @ingroup group-datatypes 28 //! C++ type in value-level representation. 29 //! 30 //! A `type` is a special kind of object representing a C++ type like 31 //! `int`, `void`, `std::vector<float>` or anything else you can imagine. 32 //! 33 //! This page explains how `type`s work at a low level. To gain 34 //! intuition about type-level metaprogramming in Hana, you should 35 //! read the [tutorial section](@ref tutorial-type) on type-level 36 //! computations. 37 //! 38 //! 39 //! @note 40 //! For subtle reasons, the actual representation of `hana::type` is 41 //! implementation-defined. In particular, `hana::type` may be a dependent 42 //! type, so one should not attempt to do pattern matching on it. However, 43 //! one can assume that `hana::type` _inherits_ from `hana::basic_type`, 44 //! which can be useful when declaring overloaded functions: 45 //! @code 46 //! template <typename T> 47 //! void f(hana::basic_type<T>) { 48 //! // do something with T 49 //! } 50 //! @endcode 51 //! The full story is that [ADL][] causes template arguments to be 52 //! instantiated. Hence, if `hana::type` were defined naively, expressions 53 //! like `hana::type<T>{} == hana::type<U>{}` would cause both `T` and `U` 54 //! to be instantiated. This is usually not a problem, except when `T` or 55 //! `U` should not be instantiated. To avoid these instantiations, 56 //! `hana::type` is implemented using some cleverness, and that is 57 //! why the representation is implementation-defined. When that 58 //! behavior is not required, `hana::basic_type` can be used instead. 59 //! 60 //! 61 //! @anchor type_lvalues_and_rvalues 62 //! Lvalues and rvalues 63 //! ------------------- 64 //! When storing `type`s in heterogeneous containers, some algorithms 65 //! will return references to those objects. Since we are primarily 66 //! interested in accessing their nested `::%type`, receiving a reference 67 //! is undesirable; we would end up trying to fetch the nested `::%type` 68 //! inside a reference type, which is a compilation error: 69 //! @code 70 //! auto ts = make_tuple(type_c<int>, type_c<char>); 71 //! using T = decltype(ts[0_c])::type; // error: 'ts[0_c]' is a reference! 72 //! @endcode 73 //! 74 //! For this reason, `type`s provide an overload of the unary `+` 75 //! operator that can be used to turn a lvalue into a rvalue. So when 76 //! using a result which might be a reference to a `type` object, one 77 //! can use `+` to make sure a rvalue is obtained before fetching its 78 //! nested `::%type`: 79 //! @code 80 //! auto ts = make_tuple(type_c<int>, type_c<char>); 81 //! using T = decltype(+ts[0_c])::type; // ok: '+ts[0_c]' is an rvalue 82 //! @endcode 83 //! 84 //! 85 //! Modeled concepts 86 //! ---------------- 87 //! 1. `Comparable`\n 88 //! Two types are equal if and only if they represent the same C++ type. 89 //! Hence, equality is equivalent to the `std::is_same` type trait. 90 //! @include example/type/comparable.cpp 91 //! 92 //! 2. `Hashable`\n 93 //! The hash of a type is just that type itself. In other words, `hash` 94 //! is the identity function on `hana::type`s. 95 //! @include example/type/hashable.cpp 96 //! 97 //! [ADL]: http://en.cppreference.com/w/cpp/language/adl 98 #ifdef BOOST_HANA_DOXYGEN_INVOKED 99 template <typename T> 100 struct type { 101 //! Returns rvalue of self. 102 //! See @ref type_lvalues_and_rvalues "description". 103 constexpr auto operator+() const; 104 105 //! Equivalent to `hana::equal` 106 template <typename X, typename Y> 107 friend constexpr auto operator==(X&& x, Y&& y); 108 109 //! Equivalent to `hana::not_equal` 110 template <typename X, typename Y> 111 friend constexpr auto operator!=(X&& x, Y&& y); 112 }; 113 #else 114 template <typename T> 115 struct type_impl; 116 117 template <typename T> 118 using type = typename type_impl<T>::_; 119 #endif 120 121 //! Tag representing `hana::type`. 122 //! @relates hana::type 123 struct type_tag { }; 124 125 //! Creates an object representing the C++ type `T`. 126 //! @relates hana::type 127 template <typename T> 128 constexpr type<T> type_c{}; 129 130 //! `decltype` keyword, lifted to Hana. 131 //! @relates hana::type 132 //! 133 //! @deprecated 134 //! The semantics of `decltype_` can be confusing, and `hana::typeid_` 135 //! should be preferred instead. `decltype_` may be removed in the next 136 //! major version of the library. 137 //! 138 //! `decltype_` is somewhat equivalent to `decltype` in that it returns 139 //! the type of an object, except it returns it as a `hana::type` which 140 //! is a first-class citizen of Hana instead of a raw C++ type. 141 //! Specifically, given an object `x`, `decltype_` satisfies 142 //! @code 143 //! decltype_(x) == type_c<decltype(x) with references stripped> 144 //! @endcode 145 //! 146 //! As you can see, `decltype_` will strip any reference from the 147 //! object's actual type. The reason for doing so is explained below. 148 //! However, any `cv`-qualifiers will be retained. Also, when given a 149 //! `hana::type`, `decltype_` is just the identity function. Hence, 150 //! for any C++ type `T`, 151 //! @code 152 //! decltype_(type_c<T>) == type_c<T> 153 //! @endcode 154 //! 155 //! In conjunction with the way `metafunction` & al. are specified, this 156 //! behavior makes it easier to interact with both types and values at 157 //! the same time. However, it does make it impossible to create a `type` 158 //! containing another `type` with `decltype_`. In other words, it is 159 //! not possible to create a `type_c<decltype(type_c<T>)>` with this 160 //! utility, because `decltype_(type_c<T>)` would be just `type_c<T>` 161 //! instead of `type_c<decltype(type_c<T>)>`. This use case is assumed 162 //! to be rare and a hand-coded function can be used if this is needed. 163 //! 164 //! 165 //! ### Rationale for stripping the references 166 //! The rules for template argument deduction are such that a perfect 167 //! solution that always matches `decltype` is impossible. Hence, we 168 //! have to settle on a solution that's good and and consistent enough 169 //! for our needs. One case where matching `decltype`'s behavior is 170 //! impossible is when the argument is a plain, unparenthesized variable 171 //! or function parameter. In that case, `decltype_`'s argument will be 172 //! deduced as a reference to that variable, but `decltype` would have 173 //! given us the actual type of that variable, without references. Also, 174 //! given the current definition of `metafunction` & al., it would be 175 //! mostly useless if `decltype_` could return a reference, because it 176 //! is unlikely that `F` expects a reference in its simplest use case: 177 //! @code 178 //! int i = 0; 179 //! auto result = metafunction<F>(i); 180 //! @endcode 181 //! 182 //! Hence, always discarding references seems to be the least painful 183 //! solution. 184 //! 185 //! 186 //! Example 187 //! ------- 188 //! @include example/type/decltype.cpp 189 #ifdef BOOST_HANA_DOXYGEN_INVOKED 190 constexpr auto decltype_ = see documentation; 191 #else 192 struct decltype_t { 193 template <typename T> 194 constexpr auto operator()(T&&) const; 195 }; 196 197 constexpr decltype_t decltype_{}; 198 #endif 199 200 //! Returns a `hana::type` representing the type of a given object. 201 //! @relates hana::type 202 //! 203 //! `hana::typeid_` is somewhat similar to `typeid` in that it returns 204 //! something that represents the type of an object. However, what 205 //! `typeid` returns represent the _runtime_ type of the object, while 206 //! `hana::typeid_` returns the _static_ type of the object. Specifically, 207 //! given an object `x`, `typeid_` satisfies 208 //! @code 209 //! typeid_(x) == type_c<decltype(x) with ref and cv-qualifiers stripped> 210 //! @endcode 211 //! 212 //! As you can see, `typeid_` strips any reference and cv-qualifier from 213 //! the object's actual type. The reason for doing so is that it faithfully 214 //! models how the language's `typeid` behaves with respect to reference 215 //! and cv-qualifiers, and it also turns out to be the desirable behavior 216 //! most of the time. Also, when given a `hana::type`, `typeid_` is just 217 //! the identity function. Hence, for any C++ type `T`, 218 //! @code 219 //! typeid_(type_c<T>) == type_c<T> 220 //! @endcode 221 //! 222 //! In conjunction with the way `metafunction` & al. are specified, this 223 //! behavior makes it easier to interact with both types and values at 224 //! the same time. However, it does make it impossible to create a `type` 225 //! containing another `type` using `typeid_`. This use case is assumed 226 //! to be rare and a hand-coded function can be used if this is needed. 227 //! 228 //! 229 //! Example 230 //! ------- 231 //! @include example/type/typeid.cpp 232 #ifdef BOOST_HANA_DOXYGEN_INVOKED 233 constexpr auto typeid_ = see documentation; 234 #else 235 struct typeid_t { 236 template <typename T> 237 constexpr auto operator()(T&&) const; 238 }; 239 240 constexpr typeid_t typeid_{}; 241 #endif 242 243 #ifdef BOOST_HANA_DOXYGEN_INVOKED 244 //! Equivalent to `decltype_`, provided for convenience. 245 //! @relates hana::type 246 //! 247 //! 248 //! Example 249 //! ------- 250 //! @include example/type/make.cpp 251 template <> 252 constexpr auto make<type_tag> = hana::decltype_; 253 #endif 254 255 //! Equivalent to `make<type_tag>`, provided for convenience. 256 //! @relates hana::type 257 //! 258 //! 259 //! Example 260 //! ------- 261 //! @include example/type/make.cpp 262 constexpr auto make_type = hana::make<type_tag>; 263 264 //! `sizeof` keyword, lifted to Hana. 265 //! @relates hana::type 266 //! 267 //! `sizeof_` is somewhat equivalent to `sizeof` in that it returns the 268 //! size of an expression or type, but it takes an arbitrary expression 269 //! or a `hana::type` and returns its size as an `integral_constant`. 270 //! Specifically, given an expression `expr`, `sizeof_` satisfies 271 //! @code 272 //! sizeof_(expr) == size_t<sizeof(decltype(expr) with references stripped)> 273 //! @endcode 274 //! 275 //! However, given a `type`, `sizeof_` will simply fetch the size 276 //! of the C++ type represented by that object. In other words, 277 //! @code 278 //! sizeof_(type_c<T>) == size_t<sizeof(T)> 279 //! @endcode 280 //! 281 //! The behavior of `sizeof_` is consistent with that of `decltype_`. 282 //! In particular, see `decltype_`'s documentation to understand why 283 //! references are always stripped by `sizeof_`. 284 //! 285 //! 286 //! Example 287 //! ------- 288 //! @include example/type/sizeof.cpp 289 #ifdef BOOST_HANA_DOXYGEN_INVOKED __anon09778f620102(auto&& x) 290 constexpr auto sizeof_ = [](auto&& x) { 291 using T = typename decltype(hana::decltype_(x))::type; 292 return hana::size_c<sizeof(T)>; 293 }; 294 #else 295 struct sizeof_t { 296 template <typename T> 297 constexpr auto operator()(T&&) const; 298 }; 299 300 constexpr sizeof_t sizeof_{}; 301 #endif 302 303 //! `alignof` keyword, lifted to Hana. 304 //! @relates hana::type 305 //! 306 //! `alignof_` is somewhat equivalent to `alignof` in that it returns the 307 //! alignment required by any instance of a type, but it takes a `type` 308 //! and returns its alignment as an `integral_constant`. Like `sizeof` 309 //! which works for expressions and type-ids, `alignof_` can also be 310 //! called on an arbitrary expression. Specifically, given an expression 311 //! `expr` and a C++ type `T`, `alignof_` satisfies 312 //! @code 313 //! alignof_(expr) == size_t<alignof(decltype(expr) with references stripped)> 314 //! alignof_(type_c<T>) == size_t<alignof(T)> 315 //! @endcode 316 //! 317 //! The behavior of `alignof_` is consistent with that of `decltype_`. 318 //! In particular, see `decltype_`'s documentation to understand why 319 //! references are always stripped by `alignof_`. 320 //! 321 //! 322 //! Example 323 //! ------- 324 //! @include example/type/alignof.cpp 325 #ifdef BOOST_HANA_DOXYGEN_INVOKED __anon09778f620202(auto&& x) 326 constexpr auto alignof_ = [](auto&& x) { 327 using T = typename decltype(hana::decltype_(x))::type; 328 return hana::size_c<alignof(T)>; 329 }; 330 #else 331 struct alignof_t { 332 template <typename T> 333 constexpr auto operator()(T&&) const; 334 }; 335 336 constexpr alignof_t alignof_{}; 337 #endif 338 339 //! Checks whether a SFINAE-friendly expression is valid. 340 //! @relates hana::type 341 //! 342 //! Given a SFINAE-friendly function, `is_valid` returns whether the 343 //! function call is valid with the given arguments. Specifically, given 344 //! a function `f` and arguments `args...`, 345 //! @code 346 //! is_valid(f, args...) == whether f(args...) is valid 347 //! @endcode 348 //! 349 //! The result is returned as a compile-time `Logical`. Furthermore, 350 //! `is_valid` can be used in curried form as follows: 351 //! @code 352 //! is_valid(f)(args...) 353 //! @endcode 354 //! 355 //! This syntax makes it easy to create functions that check the validity 356 //! of a generic expression on any given argument(s). 357 //! 358 //! @warning 359 //! To check whether calling a nullary function `f` is valid, one should 360 //! use the `is_valid(f)()` syntax. Indeed, `is_valid(f /* no args */)` 361 //! will be interpreted as the currying of `is_valid` to `f` rather than 362 //! the application of `is_valid` to `f` and no arguments. 363 //! 364 //! 365 //! Example 366 //! ------- 367 //! @include example/type/is_valid.cpp 368 #ifdef BOOST_HANA_DOXYGEN_INVOKED __anon09778f620302(auto&& f) 369 constexpr auto is_valid = [](auto&& f) { 370 return [](auto&& ...args) { 371 return whether f(args...) is a valid expression; 372 }; 373 }; 374 #else 375 struct is_valid_t { 376 template <typename F> 377 constexpr auto operator()(F&&) const; 378 379 template <typename F, typename ...Args> 380 constexpr auto operator()(F&&, Args&&...) const; 381 }; 382 383 constexpr is_valid_t is_valid{}; 384 #endif 385 386 //! Lift a template to a Metafunction. 387 //! @ingroup group-Metafunction 388 //! 389 //! Given a template class or template alias `f`, `template_<f>` is a 390 //! `Metafunction` satisfying 391 //! @code 392 //! template_<f>(type_c<x>...) == type_c<f<x...>> 393 //! decltype(template_<f>)::apply<x...>::type == f<x...> 394 //! @endcode 395 //! 396 //! @note 397 //! In a SFINAE context, the expression `template_<f>(type_c<x>...)` is 398 //! valid whenever the expression `f<x...>` is valid. 399 //! 400 //! 401 //! Example 402 //! ------- 403 //! @include example/type/template.cpp 404 #ifdef BOOST_HANA_DOXYGEN_INVOKED 405 template <template <typename ...> class F> __anon09778f620502(basic_type<T>...) 406 constexpr auto template_ = [](basic_type<T>...) { 407 return hana::type_c<F<T...>>; 408 }; 409 #else 410 template <template <typename ...> class F> 411 struct template_t; 412 413 template <template <typename ...> class F> 414 constexpr template_t<F> template_{}; 415 #endif 416 417 //! Lift a MPL-style metafunction to a Metafunction. 418 //! @ingroup group-Metafunction 419 //! 420 //! Given a MPL-style metafunction, `metafunction<f>` is a `Metafunction` 421 //! satisfying 422 //! @code 423 //! metafunction<f>(type_c<x>...) == type_c<f<x...>::type> 424 //! decltype(metafunction<f>)::apply<x...>::type == f<x...>::type 425 //! @endcode 426 //! 427 //! @note 428 //! In a SFINAE context, the expression `metafunction<f>(type_c<x>...)` is 429 //! valid whenever the expression `f<x...>::%type` is valid. 430 //! 431 //! 432 //! Example 433 //! ------- 434 //! @include example/type/metafunction.cpp 435 #ifdef BOOST_HANA_DOXYGEN_INVOKED 436 template <template <typename ...> class F> __anon09778f620602(basic_type<T>...) 437 constexpr auto metafunction = [](basic_type<T>...) { 438 return hana::type_c<typename F<T...>::type>; 439 }; 440 #else 441 template <template <typename ...> class f> 442 struct metafunction_t; 443 444 template <template <typename ...> class f> 445 constexpr metafunction_t<f> metafunction{}; 446 #endif 447 448 //! Lift a MPL-style metafunction class to a Metafunction. 449 //! @ingroup group-Metafunction 450 //! 451 //! Given a MPL-style metafunction class, `metafunction_class<f>` is a 452 //! `Metafunction` satisfying 453 //! @code 454 //! metafunction_class<f>(type_c<x>...) == type_c<f::apply<x...>::type> 455 //! decltype(metafunction_class<f>)::apply<x...>::type == f::apply<x...>::type 456 //! @endcode 457 //! 458 //! @note 459 //! In a SFINAE context, the expression `metafunction_class<f>(type_c<x>...)` 460 //! is valid whenever the expression `f::apply<x...>::%type` is valid. 461 //! 462 //! 463 //! Example 464 //! ------- 465 //! @include example/type/metafunction_class.cpp 466 #ifdef BOOST_HANA_DOXYGEN_INVOKED 467 template <typename F> __anon09778f620702(basic_type<T>...) 468 constexpr auto metafunction_class = [](basic_type<T>...) { 469 return hana::type_c<typename F::template apply<T...>::type>; 470 }; 471 #else 472 template <typename F> 473 struct metafunction_class_t; 474 475 template <typename F> 476 constexpr metafunction_class_t<F> metafunction_class{}; 477 #endif 478 479 //! Turn a `Metafunction` into a function taking `type`s and returning a 480 //! default-constructed object. 481 //! @ingroup group-Metafunction 482 //! 483 //! Given a `Metafunction` `f`, `integral` returns a new `Metafunction` 484 //! that default-constructs an object of the type returned by `f`. More 485 //! specifically, the following holds: 486 //! @code 487 //! integral(f)(t...) == decltype(f(t...))::type{} 488 //! @endcode 489 //! 490 //! The principal use case for `integral` is to transform `Metafunction`s 491 //! returning a type that inherits from a meaningful base like 492 //! `std::integral_constant` into functions returning e.g. a 493 //! `hana::integral_constant`. 494 //! 495 //! @note 496 //! - This is not a `Metafunction` because it does not return a `type`. 497 //! As such, it would not make sense to make `decltype(integral(f))` 498 //! a MPL metafunction class like the usual `Metafunction`s are. 499 //! 500 //! - When using `integral` with metafunctions returning 501 //! `std::integral_constant`s, don't forget to include the 502 //! boost/hana/ext/std/integral_constant.hpp header to ensure 503 //! Hana can interoperate with the result. 504 //! 505 //! - In a SFINAE context, the expression `integral(f)(t...)` is valid 506 //! whenever the expression `decltype(f(t...))::%type` is valid. 507 //! 508 //! 509 //! Example 510 //! ------- 511 //! @include example/type/integral.cpp 512 #ifdef BOOST_HANA_DOXYGEN_INVOKED __anon09778f620802(auto f) 513 constexpr auto integral = [](auto f) { 514 return [](basic_type<T>...) { 515 return decltype(f)::apply<T...>::type{}; 516 }; 517 }; 518 #else 519 template <typename F> 520 struct integral_t; 521 522 struct make_integral_t { 523 template <typename F> operator ()make_integral_t524 constexpr integral_t<F> operator()(F const&) const 525 { return {}; } 526 }; 527 528 constexpr make_integral_t integral{}; 529 #endif 530 531 //! Alias to `integral(metafunction<F>)`, provided for convenience. 532 //! @ingroup group-Metafunction 533 //! 534 //! 535 //! Example 536 //! ------- 537 //! @include example/type/trait.cpp 538 template <template <typename ...> class F> 539 constexpr auto trait = hana::integral(hana::metafunction<F>); 540 BOOST_HANA_NAMESPACE_END 541 542 #endif // !BOOST_HANA_FWD_TYPE_HPP 543