| 1 | /*! |
| 2 | @file |
| 3 | Forward declares `boost::hana::common` and `boost::hana::common_t`. |
| 4 | |
| 5 | Copyright Louis Dionne 2013-2022 |
| 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_CORE_COMMON_HPP |
| 11 | #define BOOST_HANA_FWD_CORE_COMMON_HPP |
| 12 | |
| 13 | #include <boost/hana/config.hpp> |
| 14 | |
| 15 | |
| 16 | namespace boost { namespace hana { |
| 17 | //! @ingroup group-core |
| 18 | //! %Metafunction returning the common data type between two data types. |
| 19 | //! |
| 20 | //! `common` is a natural extension of the `std::common_type` metafunction |
| 21 | //! to data types. Given two data types `T` and `U`, we say that they share |
| 22 | //! a common type `C` if both objects of data type `T` and objects of data |
| 23 | //! type `U` may be converted (using `to`) to an object of data type `C`, |
| 24 | //! and if that conversion is equality preserving. In other words, this |
| 25 | //! means that for any objects `t1, t2` of data type `T` and `u1, u2` of |
| 26 | //! data type `U`, the following law is satisfied: |
| 27 | //! @code |
| 28 | //! to<C>(t1) == to<C>(t2) if and only if t1 == t2 |
| 29 | //! to<C>(u1) == to<C>(u2) if and only if u1 == u2 |
| 30 | //! @endcode |
| 31 | //! |
| 32 | //! The role of `common` is to provide an alias to such a `C` if it exists. |
| 33 | //! In other words, if `T` and `U` have a common data type `C`, |
| 34 | //! `common<T, U>::%type` is an alias to `C`. Otherwise, `common<T, U>` |
| 35 | //! has no nested `type` and can be used in dependent contexts to exploit |
| 36 | //! SFINAE. By default, the exact steps followed by `common` to determine |
| 37 | //! the common type `C` of `T` and `U` are |
| 38 | //! 1. If `T` and `U` are the same, then `C` is `T`. |
| 39 | //! 2. Otherwise, if `true ? std::declval<T>() : std::declval<U>()` is |
| 40 | //! well-formed, then `C` is the type of this expression after using |
| 41 | //! `std::decay` on it. This is exactly the type that would have been |
| 42 | //! returned by `std::common_type`, except that custom specializations |
| 43 | //! of `std::common_type` are not taken into account. |
| 44 | //! 3. Otherwise, no common data type is detected and `common<T, U>` does |
| 45 | //! not have a nested `type` alias, unless it is specialized explicitly. |
| 46 | //! |
| 47 | //! As point 3 suggests, it is also possible (and sometimes necessary) to |
| 48 | //! specialize `common` in the `boost::hana` namespace for pairs of custom |
| 49 | //! data types when the default behavior of `common` is not sufficient. |
| 50 | //! Note that `when`-based specialization is supported when specializing |
| 51 | //! `common` in the `boost::hana` namespace. |
| 52 | //! |
| 53 | //! > #### Rationale for requiring the conversion to be equality-preserving |
| 54 | //! > This decision is aligned with a proposed concept design for the |
| 55 | //! > standard library ([N3351][1]). Also, if we did not require this, |
| 56 | //! > then all data types would trivially share the common data type |
| 57 | //! > `void`, since all objects can be converted to it. |
| 58 | //! |
| 59 | //! |
| 60 | //! Example |
| 61 | //! ------- |
| 62 | //! @include example/core/common/common.cpp |
| 63 | //! |
| 64 | //! |
| 65 | //! [1]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3351.pdf |
| 66 | #ifdef BOOST_HANA_DOXYGEN_INVOKED |
| 67 | template <typename T, typename U, optional when-based enabler> |
| 68 | struct common { see documentation }; |
| 69 | #else |
| 70 | template <typename T, typename U, typename = void> |
| 71 | struct common; |
| 72 | #endif |
| 73 | |
| 74 | //! @ingroup group-core |
| 75 | //! %Metafunction returning whether two data types share a common data type. |
| 76 | //! |
| 77 | //! Given two data types `T` and `U`, this metafunction simply returns |
| 78 | //! whether `common<T, U>::%type` is well-formed. |
| 79 | //! |
| 80 | //! |
| 81 | //! Example |
| 82 | //! ------- |
| 83 | //! @include example/core/common/has_common.cpp |
| 84 | #ifdef BOOST_HANA_DOXYGEN_INVOKED |
| 85 | template <typename T, typename U> |
| 86 | struct has_common { whether common<T, U>::type is well-formed }; |
| 87 | #else |
| 88 | template <typename T, typename U, typename = void> |
| 89 | struct has_common; |
| 90 | #endif |
| 91 | |
| 92 | //! @ingroup group-core |
| 93 | //! Alias to `common<T, U>::%type`, provided for convenience. |
| 94 | //! |
| 95 | //! |
| 96 | //! Example |
| 97 | //! ------- |
| 98 | //! @include example/core/common/common_t.cpp |
| 99 | template <typename T, typename U> |
| 100 | using common_t = typename common<T, U>::type; |
| 101 | }} // end namespace boost::hana |
| 102 | |
| 103 | #endif // !BOOST_HANA_FWD_CORE_COMMON_HPP |
| 104 | |