|
|
|||
File indexing completed on 2025-12-15 09:53:05
0001 /*! 0002 @file 0003 Forward declares `boost::hana::type` and related utilities. 0004 0005 Copyright Louis Dionne 2013-2022 0006 Distributed under the Boost Software License, Version 1.0. 0007 (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 0008 */ 0009 0010 #ifndef BOOST_HANA_FWD_TYPE_HPP 0011 #define BOOST_HANA_FWD_TYPE_HPP 0012 0013 #include <boost/hana/config.hpp> 0014 #include <boost/hana/fwd/core/make.hpp> 0015 0016 0017 namespace boost { namespace hana { 0018 //! Base class of `hana::type`; used for pattern-matching. 0019 //! @relates hana::type 0020 //! 0021 //! Example 0022 //! ------- 0023 //! @include example/type/basic_type.cpp 0024 template <typename T> 0025 struct basic_type; 0026 0027 //! @ingroup group-datatypes 0028 //! C++ type in value-level representation. 0029 //! 0030 //! A `type` is a special kind of object representing a C++ type like 0031 //! `int`, `void`, `std::vector<float>` or anything else you can imagine. 0032 //! 0033 //! This page explains how `type`s work at a low level. To gain 0034 //! intuition about type-level metaprogramming in Hana, you should 0035 //! read the [tutorial section](@ref tutorial-type) on type-level 0036 //! computations. 0037 //! 0038 //! 0039 //! @note 0040 //! For subtle reasons, the actual representation of `hana::type` is 0041 //! implementation-defined. In particular, `hana::type` may be a dependent 0042 //! type, so one should not attempt to do pattern matching on it. However, 0043 //! one can assume that `hana::type` _inherits_ from `hana::basic_type`, 0044 //! which can be useful when declaring overloaded functions: 0045 //! @code 0046 //! template <typename T> 0047 //! void f(hana::basic_type<T>) { 0048 //! // do something with T 0049 //! } 0050 //! @endcode 0051 //! The full story is that [ADL][] causes template arguments to be 0052 //! instantiated. Hence, if `hana::type` were defined naively, expressions 0053 //! like `hana::type<T>{} == hana::type<U>{}` would cause both `T` and `U` 0054 //! to be instantiated. This is usually not a problem, except when `T` or 0055 //! `U` should not be instantiated. To avoid these instantiations, 0056 //! `hana::type` is implemented using some cleverness, and that is 0057 //! why the representation is implementation-defined. When that 0058 //! behavior is not required, `hana::basic_type` can be used instead. 0059 //! 0060 //! 0061 //! @anchor type_lvalues_and_rvalues 0062 //! Lvalues and rvalues 0063 //! ------------------- 0064 //! When storing `type`s in heterogeneous containers, some algorithms 0065 //! will return references to those objects. Since we are primarily 0066 //! interested in accessing their nested `::%type`, receiving a reference 0067 //! is undesirable; we would end up trying to fetch the nested `::%type` 0068 //! inside a reference type, which is a compilation error: 0069 //! @code 0070 //! auto ts = make_tuple(type_c<int>, type_c<char>); 0071 //! using T = decltype(ts[0_c])::type; // error: 'ts[0_c]' is a reference! 0072 //! @endcode 0073 //! 0074 //! For this reason, `type`s provide an overload of the unary `+` 0075 //! operator that can be used to turn a lvalue into a rvalue. So when 0076 //! using a result which might be a reference to a `type` object, one 0077 //! can use `+` to make sure a rvalue is obtained before fetching its 0078 //! nested `::%type`: 0079 //! @code 0080 //! auto ts = make_tuple(type_c<int>, type_c<char>); 0081 //! using T = decltype(+ts[0_c])::type; // ok: '+ts[0_c]' is an rvalue 0082 //! @endcode 0083 //! 0084 //! 0085 //! Modeled concepts 0086 //! ---------------- 0087 //! 1. `Comparable`\n 0088 //! Two types are equal if and only if they represent the same C++ type. 0089 //! Hence, equality is equivalent to the `std::is_same` type trait. 0090 //! @include example/type/comparable.cpp 0091 //! 0092 //! 2. `Hashable`\n 0093 //! The hash of a type is just that type itself. In other words, `hash` 0094 //! is the identity function on `hana::type`s. 0095 //! @include example/type/hashable.cpp 0096 //! 0097 //! [ADL]: http://en.cppreference.com/w/cpp/language/adl 0098 #ifdef BOOST_HANA_DOXYGEN_INVOKED 0099 template <typename T> 0100 struct type { 0101 //! Returns rvalue of self. 0102 //! See @ref type_lvalues_and_rvalues "description". 0103 constexpr auto operator+() const; 0104 0105 //! Equivalent to `hana::equal` 0106 template <typename X, typename Y> 0107 friend constexpr auto operator==(X&& x, Y&& y); 0108 0109 //! Equivalent to `hana::not_equal` 0110 template <typename X, typename Y> 0111 friend constexpr auto operator!=(X&& x, Y&& y); 0112 }; 0113 #else 0114 template <typename T> 0115 struct type_impl; 0116 0117 template <typename T> 0118 using type = typename type_impl<T>::_; 0119 #endif 0120 0121 //! Tag representing `hana::type`. 0122 //! @relates hana::type 0123 struct type_tag { }; 0124 0125 //! Creates an object representing the C++ type `T`. 0126 //! @relates hana::type 0127 template <typename T> 0128 BOOST_HANA_INLINE_VARIABLE constexpr type<T> type_c{}; 0129 0130 //! `decltype` keyword, lifted to Hana. 0131 //! @relates hana::type 0132 //! 0133 //! @deprecated 0134 //! The semantics of `decltype_` can be confusing, and `hana::typeid_` 0135 //! should be preferred instead. `decltype_` may be removed in the next 0136 //! major version of the library. 0137 //! 0138 //! `decltype_` is somewhat equivalent to `decltype` in that it returns 0139 //! the type of an object, except it returns it as a `hana::type` which 0140 //! is a first-class citizen of Hana instead of a raw C++ type. 0141 //! Specifically, given an object `x`, `decltype_` satisfies 0142 //! @code 0143 //! decltype_(x) == type_c<decltype(x) with references stripped> 0144 //! @endcode 0145 //! 0146 //! As you can see, `decltype_` will strip any reference from the 0147 //! object's actual type. The reason for doing so is explained below. 0148 //! However, any `cv`-qualifiers will be retained. Also, when given a 0149 //! `hana::type`, `decltype_` is just the identity function. Hence, 0150 //! for any C++ type `T`, 0151 //! @code 0152 //! decltype_(type_c<T>) == type_c<T> 0153 //! @endcode 0154 //! 0155 //! In conjunction with the way `metafunction` & al. are specified, this 0156 //! behavior makes it easier to interact with both types and values at 0157 //! the same time. However, it does make it impossible to create a `type` 0158 //! containing another `type` with `decltype_`. In other words, it is 0159 //! not possible to create a `type_c<decltype(type_c<T>)>` with this 0160 //! utility, because `decltype_(type_c<T>)` would be just `type_c<T>` 0161 //! instead of `type_c<decltype(type_c<T>)>`. This use case is assumed 0162 //! to be rare and a hand-coded function can be used if this is needed. 0163 //! 0164 //! 0165 //! ### Rationale for stripping the references 0166 //! The rules for template argument deduction are such that a perfect 0167 //! solution that always matches `decltype` is impossible. Hence, we 0168 //! have to settle on a solution that's good and and consistent enough 0169 //! for our needs. One case where matching `decltype`'s behavior is 0170 //! impossible is when the argument is a plain, unparenthesized variable 0171 //! or function parameter. In that case, `decltype_`'s argument will be 0172 //! deduced as a reference to that variable, but `decltype` would have 0173 //! given us the actual type of that variable, without references. Also, 0174 //! given the current definition of `metafunction` & al., it would be 0175 //! mostly useless if `decltype_` could return a reference, because it 0176 //! is unlikely that `F` expects a reference in its simplest use case: 0177 //! @code 0178 //! int i = 0; 0179 //! auto result = metafunction<F>(i); 0180 //! @endcode 0181 //! 0182 //! Hence, always discarding references seems to be the least painful 0183 //! solution. 0184 //! 0185 //! 0186 //! Example 0187 //! ------- 0188 //! @include example/type/decltype.cpp 0189 #ifdef BOOST_HANA_DOXYGEN_INVOKED 0190 constexpr auto decltype_ = see documentation; 0191 #else 0192 struct decltype_t { 0193 template <typename T> 0194 constexpr auto operator()(T&&) const; 0195 }; 0196 0197 BOOST_HANA_INLINE_VARIABLE constexpr decltype_t decltype_{}; 0198 #endif 0199 0200 //! Returns a `hana::type` representing the type of a given object. 0201 //! @relates hana::type 0202 //! 0203 //! `hana::typeid_` is somewhat similar to `typeid` in that it returns 0204 //! something that represents the type of an object. However, what 0205 //! `typeid` returns represent the _runtime_ type of the object, while 0206 //! `hana::typeid_` returns the _static_ type of the object. Specifically, 0207 //! given an object `x`, `typeid_` satisfies 0208 //! @code 0209 //! typeid_(x) == type_c<decltype(x) with ref and cv-qualifiers stripped> 0210 //! @endcode 0211 //! 0212 //! As you can see, `typeid_` strips any reference and cv-qualifier from 0213 //! the object's actual type. The reason for doing so is that it faithfully 0214 //! models how the language's `typeid` behaves with respect to reference 0215 //! and cv-qualifiers, and it also turns out to be the desirable behavior 0216 //! most of the time. Also, when given a `hana::type`, `typeid_` is just 0217 //! the identity function. Hence, for any C++ type `T`, 0218 //! @code 0219 //! typeid_(type_c<T>) == type_c<T> 0220 //! @endcode 0221 //! 0222 //! In conjunction with the way `metafunction` & al. are specified, this 0223 //! behavior makes it easier to interact with both types and values at 0224 //! the same time. However, it does make it impossible to create a `type` 0225 //! containing another `type` using `typeid_`. This use case is assumed 0226 //! to be rare and a hand-coded function can be used if this is needed. 0227 //! 0228 //! 0229 //! Example 0230 //! ------- 0231 //! @include example/type/typeid.cpp 0232 #ifdef BOOST_HANA_DOXYGEN_INVOKED 0233 constexpr auto typeid_ = see documentation; 0234 #else 0235 struct typeid_t { 0236 template <typename T> 0237 constexpr auto operator()(T&&) const; 0238 }; 0239 0240 BOOST_HANA_INLINE_VARIABLE constexpr typeid_t typeid_{}; 0241 #endif 0242 0243 #ifdef BOOST_HANA_DOXYGEN_INVOKED 0244 //! Equivalent to `decltype_`, provided for convenience. 0245 //! @relates hana::type 0246 //! 0247 //! 0248 //! Example 0249 //! ------- 0250 //! @include example/type/make.cpp 0251 template <> 0252 constexpr auto make<type_tag> = hana::decltype_; 0253 #endif 0254 0255 //! Equivalent to `make<type_tag>`, provided for convenience. 0256 //! @relates hana::type 0257 //! 0258 //! 0259 //! Example 0260 //! ------- 0261 //! @include example/type/make.cpp 0262 BOOST_HANA_INLINE_VARIABLE constexpr auto make_type = hana::make<type_tag>; 0263 0264 //! `sizeof` keyword, lifted to Hana. 0265 //! @relates hana::type 0266 //! 0267 //! `sizeof_` is somewhat equivalent to `sizeof` in that it returns the 0268 //! size of an expression or type, but it takes an arbitrary expression 0269 //! or a `hana::type` and returns its size as an `integral_constant`. 0270 //! Specifically, given an expression `expr`, `sizeof_` satisfies 0271 //! @code 0272 //! sizeof_(expr) == size_t<sizeof(decltype(expr) with references stripped)> 0273 //! @endcode 0274 //! 0275 //! However, given a `type`, `sizeof_` will simply fetch the size 0276 //! of the C++ type represented by that object. In other words, 0277 //! @code 0278 //! sizeof_(type_c<T>) == size_t<sizeof(T)> 0279 //! @endcode 0280 //! 0281 //! The behavior of `sizeof_` is consistent with that of `decltype_`. 0282 //! In particular, see `decltype_`'s documentation to understand why 0283 //! references are always stripped by `sizeof_`. 0284 //! 0285 //! 0286 //! Example 0287 //! ------- 0288 //! @include example/type/sizeof.cpp 0289 #ifdef BOOST_HANA_DOXYGEN_INVOKED 0290 constexpr auto sizeof_ = [](auto&& x) { 0291 using T = typename decltype(hana::decltype_(x))::type; 0292 return hana::size_c<sizeof(T)>; 0293 }; 0294 #else 0295 struct sizeof_t { 0296 template <typename T> 0297 constexpr auto operator()(T&&) const; 0298 }; 0299 0300 BOOST_HANA_INLINE_VARIABLE constexpr sizeof_t sizeof_{}; 0301 #endif 0302 0303 //! `alignof` keyword, lifted to Hana. 0304 //! @relates hana::type 0305 //! 0306 //! `alignof_` is somewhat equivalent to `alignof` in that it returns the 0307 //! alignment required by any instance of a type, but it takes a `type` 0308 //! and returns its alignment as an `integral_constant`. Like `sizeof` 0309 //! which works for expressions and type-ids, `alignof_` can also be 0310 //! called on an arbitrary expression. Specifically, given an expression 0311 //! `expr` and a C++ type `T`, `alignof_` satisfies 0312 //! @code 0313 //! alignof_(expr) == size_t<alignof(decltype(expr) with references stripped)> 0314 //! alignof_(type_c<T>) == size_t<alignof(T)> 0315 //! @endcode 0316 //! 0317 //! The behavior of `alignof_` is consistent with that of `decltype_`. 0318 //! In particular, see `decltype_`'s documentation to understand why 0319 //! references are always stripped by `alignof_`. 0320 //! 0321 //! 0322 //! Example 0323 //! ------- 0324 //! @include example/type/alignof.cpp 0325 #ifdef BOOST_HANA_DOXYGEN_INVOKED 0326 constexpr auto alignof_ = [](auto&& x) { 0327 using T = typename decltype(hana::decltype_(x))::type; 0328 return hana::size_c<alignof(T)>; 0329 }; 0330 #else 0331 struct alignof_t { 0332 template <typename T> 0333 constexpr auto operator()(T&&) const; 0334 }; 0335 0336 BOOST_HANA_INLINE_VARIABLE constexpr alignof_t alignof_{}; 0337 #endif 0338 0339 //! Checks whether a SFINAE-friendly expression is valid. 0340 //! @relates hana::type 0341 //! 0342 //! Given a SFINAE-friendly function, `is_valid` returns whether the 0343 //! function call is valid with the given arguments. Specifically, given 0344 //! a function `f` and arguments `args...`, 0345 //! @code 0346 //! is_valid(f, args...) == whether f(args...) is valid 0347 //! @endcode 0348 //! 0349 //! The result is returned as a compile-time `Logical`. Furthermore, 0350 //! `is_valid` can be used in curried form as follows: 0351 //! @code 0352 //! is_valid(f)(args...) 0353 //! @endcode 0354 //! 0355 //! This syntax makes it easy to create functions that check the validity 0356 //! of a generic expression on any given argument(s). 0357 //! 0358 //! @warning 0359 //! To check whether calling a nullary function `f` is valid, one should 0360 //! use the `is_valid(f)()` syntax. Indeed, `is_valid(f /* no args */)` 0361 //! will be interpreted as the currying of `is_valid` to `f` rather than 0362 //! the application of `is_valid` to `f` and no arguments. 0363 //! 0364 //! 0365 //! Example 0366 //! ------- 0367 //! @include example/type/is_valid.cpp 0368 #ifdef BOOST_HANA_DOXYGEN_INVOKED 0369 constexpr auto is_valid = [](auto&& f) { 0370 return [](auto&& ...args) { 0371 return whether f(args...) is a valid expression; 0372 }; 0373 }; 0374 #else 0375 struct is_valid_t { 0376 template <typename F> 0377 constexpr auto operator()(F&&) const; 0378 0379 template <typename F, typename ...Args> 0380 constexpr auto operator()(F&&, Args&&...) const; 0381 }; 0382 0383 BOOST_HANA_INLINE_VARIABLE constexpr is_valid_t is_valid{}; 0384 #endif 0385 0386 //! Lift a template to a Metafunction. 0387 //! @ingroup group-Metafunction 0388 //! 0389 //! Given a template class or template alias `f`, `template_<f>` is a 0390 //! `Metafunction` satisfying 0391 //! @code 0392 //! template_<f>(type_c<x>...) == type_c<f<x...>> 0393 //! decltype(template_<f>)::apply<x...>::type == f<x...> 0394 //! @endcode 0395 //! 0396 //! @note 0397 //! In a SFINAE context, the expression `template_<f>(type_c<x>...)` is 0398 //! valid whenever the expression `f<x...>` is valid. 0399 //! 0400 //! 0401 //! Example 0402 //! ------- 0403 //! @include example/type/template.cpp 0404 #ifdef BOOST_HANA_DOXYGEN_INVOKED 0405 template <template <typename ...> class F> 0406 constexpr auto template_ = [](basic_type<T>...) { 0407 return hana::type_c<F<T...>>; 0408 }; 0409 #else 0410 template <template <typename ...> class F> 0411 struct template_t; 0412 0413 template <template <typename ...> class F> 0414 BOOST_HANA_INLINE_VARIABLE constexpr template_t<F> template_{}; 0415 #endif 0416 0417 //! Lift a MPL-style metafunction to a Metafunction. 0418 //! @ingroup group-Metafunction 0419 //! 0420 //! Given a MPL-style metafunction, `metafunction<f>` is a `Metafunction` 0421 //! satisfying 0422 //! @code 0423 //! metafunction<f>(type_c<x>...) == type_c<f<x...>::type> 0424 //! decltype(metafunction<f>)::apply<x...>::type == f<x...>::type 0425 //! @endcode 0426 //! 0427 //! @note 0428 //! In a SFINAE context, the expression `metafunction<f>(type_c<x>...)` is 0429 //! valid whenever the expression `f<x...>::%type` is valid. 0430 //! 0431 //! 0432 //! Example 0433 //! ------- 0434 //! @include example/type/metafunction.cpp 0435 #ifdef BOOST_HANA_DOXYGEN_INVOKED 0436 template <template <typename ...> class F> 0437 constexpr auto metafunction = [](basic_type<T>...) { 0438 return hana::type_c<typename F<T...>::type>; 0439 }; 0440 #else 0441 template <template <typename ...> class f> 0442 struct metafunction_t; 0443 0444 template <template <typename ...> class f> 0445 BOOST_HANA_INLINE_VARIABLE constexpr metafunction_t<f> metafunction{}; 0446 #endif 0447 0448 //! Lift a MPL-style metafunction class to a Metafunction. 0449 //! @ingroup group-Metafunction 0450 //! 0451 //! Given a MPL-style metafunction class, `metafunction_class<f>` is a 0452 //! `Metafunction` satisfying 0453 //! @code 0454 //! metafunction_class<f>(type_c<x>...) == type_c<f::apply<x...>::type> 0455 //! decltype(metafunction_class<f>)::apply<x...>::type == f::apply<x...>::type 0456 //! @endcode 0457 //! 0458 //! @note 0459 //! In a SFINAE context, the expression `metafunction_class<f>(type_c<x>...)` 0460 //! is valid whenever the expression `f::apply<x...>::%type` is valid. 0461 //! 0462 //! 0463 //! Example 0464 //! ------- 0465 //! @include example/type/metafunction_class.cpp 0466 #ifdef BOOST_HANA_DOXYGEN_INVOKED 0467 template <typename F> 0468 constexpr auto metafunction_class = [](basic_type<T>...) { 0469 return hana::type_c<typename F::template apply<T...>::type>; 0470 }; 0471 #else 0472 template <typename F> 0473 struct metafunction_class_t; 0474 0475 template <typename F> 0476 BOOST_HANA_INLINE_VARIABLE constexpr metafunction_class_t<F> metafunction_class{}; 0477 #endif 0478 0479 //! Turn a `Metafunction` into a function taking `type`s and returning a 0480 //! default-constructed object. 0481 //! @ingroup group-Metafunction 0482 //! 0483 //! Given a `Metafunction` `f`, `integral` returns a new `Metafunction` 0484 //! that default-constructs an object of the type returned by `f`. More 0485 //! specifically, the following holds: 0486 //! @code 0487 //! integral(f)(t...) == decltype(f(t...))::type{} 0488 //! @endcode 0489 //! 0490 //! The principal use case for `integral` is to transform `Metafunction`s 0491 //! returning a type that inherits from a meaningful base like 0492 //! `std::integral_constant` into functions returning e.g. a 0493 //! `hana::integral_constant`. 0494 //! 0495 //! @note 0496 //! - This is not a `Metafunction` because it does not return a `type`. 0497 //! As such, it would not make sense to make `decltype(integral(f))` 0498 //! a MPL metafunction class like the usual `Metafunction`s are. 0499 //! 0500 //! - When using `integral` with metafunctions returning 0501 //! `std::integral_constant`s, don't forget to include the 0502 //! boost/hana/ext/std/integral_constant.hpp header to ensure 0503 //! Hana can interoperate with the result. 0504 //! 0505 //! - In a SFINAE context, the expression `integral(f)(t...)` is valid 0506 //! whenever the expression `decltype(f(t...))::%type` is valid. 0507 //! 0508 //! 0509 //! Example 0510 //! ------- 0511 //! @include example/type/integral.cpp 0512 #ifdef BOOST_HANA_DOXYGEN_INVOKED 0513 constexpr auto integral = [](auto f) { 0514 return [](basic_type<T>...) { 0515 return decltype(f)::apply<T...>::type{}; 0516 }; 0517 }; 0518 #else 0519 template <typename F> 0520 struct integral_t; 0521 0522 struct make_integral_t { 0523 template <typename F> 0524 constexpr integral_t<F> operator()(F const&) const 0525 { return {}; } 0526 }; 0527 0528 BOOST_HANA_INLINE_VARIABLE constexpr make_integral_t integral{}; 0529 #endif 0530 0531 //! Alias to `integral(metafunction<F>)`, provided for convenience. 0532 //! @ingroup group-Metafunction 0533 //! 0534 //! 0535 //! Example 0536 //! ------- 0537 //! @include example/type/trait.cpp 0538 template <template <typename ...> class F> 0539 BOOST_HANA_INLINE_VARIABLE constexpr auto trait = hana::integral(hana::metafunction<F>); 0540 }} // end namespace boost::hana 0541 0542 #endif // !BOOST_HANA_FWD_TYPE_HPP
| [ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
|
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
|