1 /*!
2 @file
3 Forward declares `boost::hana::common` and `boost::hana::common_t`.
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_CORE_COMMON_HPP
11 #define BOOST_HANA_FWD_CORE_COMMON_HPP
12 
13 #include <boost/hana/config.hpp>
14 
15 
16 BOOST_HANA_NAMESPACE_BEGIN
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 BOOST_HANA_NAMESPACE_END
102 
103 #endif // !BOOST_HANA_FWD_CORE_COMMON_HPP
104