1 /*=============================================================================
2 Copyright (c) 2015 Paul Fultz II
3 alias.h
4 Distributed under the Boost Software License, Version 1.0. (See accompanying
5 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 ==============================================================================*/
7
8 #ifndef BOOST_HOF_GUARD_ALIAS_H
9 #define BOOST_HOF_GUARD_ALIAS_H
10
11 #include <boost/hof/returns.hpp>
12 #include <boost/hof/detail/delegate.hpp>
13 #include <boost/hof/detail/move.hpp>
14 #include <boost/hof/detail/holder.hpp>
15 #include <boost/hof/config.hpp>
16
17 /// alias
18 /// =====
19 ///
20 /// Description
21 /// -----------
22 ///
23 /// The `alias` class wraps a type with a new type that can be tagged by the
24 /// user. This allows defining extra attributes about the type outside of the
25 /// type itself. There are three different ways the value can be stored: as a
26 /// member variable, by inheritance, or as a static member variable. The value
27 /// can be retrieved uniformily using the `alias_value` function.
28 ///
29 /// Synopsis
30 /// --------
31 ///
32 /// // Alias the type using a member variable
33 /// template<class T, class Tag=void>
34 /// class alias;
35 ///
36 /// // Alias the type by inheriting
37 /// template<class T, class Tag=void>
38 /// class alias_inherit;
39 ///
40 /// // Alias the type using a static variable
41 /// template<class T, class Tag=void>
42 /// class alias_static;
43 ///
44 /// // Retrieve tag from alias
45 /// template<class Alias>
46 /// class alias_tag;
47 ///
48 /// // Check if type has a certian tag
49 /// template<class T, class Tag>
50 /// class has_tag;
51 ///
52 /// // Retrieve value from alias
53 /// template<class Alias>
54 /// constexpr auto alias_value(Alias&&);
55 ///
56
57 #ifdef _MSC_VER
58 #pragma warning(push)
59 #pragma warning(disable: 4579)
60 #endif
61
62 namespace boost { namespace hof {
63
64 template<class T>
65 struct alias_tag;
66
67 template<class T, class Tag, class=void>
68 struct has_tag
69 : std::false_type
70 {};
71
72 template<class T, class Tag>
73 struct has_tag<T, Tag, typename detail::holder<
74 typename alias_tag<T>::type
75 >::type>
76 : std::is_same<typename alias_tag<T>::type, Tag>
77 {};
78
79 namespace detail {
80
81 template<class T>
lvalue(T & x)82 constexpr T& lvalue(T& x) noexcept
83 {
84 return x;
85 }
86
87 template<class T>
lvalue(const T & x)88 constexpr const T& lvalue(const T& x) noexcept
89 {
90 return x;
91 }
92
93 }
94
95 #define BOOST_HOF_UNARY_PERFECT_FOREACH(m) \
96 m(const&, boost::hof::detail::lvalue) \
97 m(&, boost::hof::detail::lvalue) \
98 m(&&, boost::hof::move) \
99
100 template<class T, class Tag=void>
101 struct alias
102 {
103 T value;
104 BOOST_HOF_DELEGATE_CONSTRUCTOR(alias, T, value)
105 };
106
107 #define BOOST_HOF_DETAIL_ALIAS_GET_VALUE(ref, move) \
108 template<class Tag, class T, class... Ts> \
109 constexpr auto alias_value(alias<T, Tag> ref a, Ts&&...) BOOST_HOF_RETURNS(move(a.value))
110 BOOST_HOF_UNARY_PERFECT_FOREACH(BOOST_HOF_DETAIL_ALIAS_GET_VALUE)
111
112 template<class T, class Tag>
113 struct alias_tag<alias<T, Tag>>
114 { typedef Tag type; };
115
116
117 template<class T, class Tag=void>
118 struct alias_inherit
119 #if (defined(__GNUC__) && !defined (__clang__))
120 : std::conditional<(std::is_class<T>::value), T, alias<T>>::type
121 #else
122 : T
123 #endif
124 {
125 BOOST_HOF_INHERIT_CONSTRUCTOR(alias_inherit, T)
126 };
127
128 #define BOOST_HOF_DETAIL_ALIAS_INHERIT_GET_VALUE(ref, move) \
129 template<class Tag, class T, class... Ts, class=typename std::enable_if<(BOOST_HOF_IS_CLASS(T))>::type> \
130 constexpr T ref alias_value(alias_inherit<T, Tag> ref a, Ts&&...) BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT(move(a)) \
131 { \
132 return move(a); \
133 }
134 BOOST_HOF_UNARY_PERFECT_FOREACH(BOOST_HOF_DETAIL_ALIAS_INHERIT_GET_VALUE)
135
136 template<class T, class Tag>
137 struct alias_tag<alias_inherit<T, Tag>>
138 { typedef Tag type; };
139
140 namespace detail {
141
142 template<class T, class Tag>
143 struct alias_static_storage
144 {
145 #ifdef _MSC_VER
146 // Since we disable the error for 4579 on MSVC, which leaves the static
147 // member unitialized at runtime, it is, therefore, only safe to use this
148 // class on types that are empty with constructors that have no possible
149 // side effects.
150 static_assert(BOOST_HOF_IS_EMPTY(T) &&
151 BOOST_HOF_IS_LITERAL(T) &&
152 BOOST_HOF_IS_DEFAULT_CONSTRUCTIBLE(T), "In-class initialization is not yet implemented on MSVC");
153 #endif
154 static constexpr T value = T();
155 };
156
157 template<class T, class Tag>
158 constexpr T alias_static_storage<T, Tag>::value;
159
160 }
161
162 template<class T, class Tag=void>
163 struct alias_static
164 {
165 template<class... Ts, BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(T, Ts...)>
alias_staticboost::hof::alias_static166 constexpr alias_static(Ts&&...) noexcept
167 {}
168 };
169
170 template<class Tag, class T, class... Ts>
alias_value(const alias_static<T,Tag> &,Ts &&...)171 constexpr const T& alias_value(const alias_static<T, Tag>&, Ts&&...) noexcept
172 {
173 return detail::alias_static_storage<T, Tag>::value;
174 }
175
176 template<class T, class Tag>
177 struct alias_tag<alias_static<T, Tag>>
178 { typedef Tag type; };
179
180 namespace detail {
181
182 template<class T, class Tag>
183 struct alias_try_inherit
184 : std::conditional<(BOOST_HOF_IS_CLASS(T) && !BOOST_HOF_IS_FINAL(T) && !BOOST_HOF_IS_POLYMORPHIC(T)),
185 alias_inherit<T, Tag>,
186 alias<T, Tag>
187 >
188 {};
189
190 #if BOOST_HOF_HAS_EBO
191 template<class T, class Tag>
192 struct alias_empty
193 : std::conditional<(BOOST_HOF_IS_EMPTY(T)),
194 typename alias_try_inherit<T, Tag>::type,
195 alias<T, Tag>
196 >
197 {};
198 #else
199 template<class T, class Tag>
200 struct alias_empty
201 : std::conditional<
202 BOOST_HOF_IS_EMPTY(T) &&
203 BOOST_HOF_IS_LITERAL(T) &&
204 BOOST_HOF_IS_DEFAULT_CONSTRUCTIBLE(T),
205 alias_static<T, Tag>,
206 alias<T, Tag>
207 >
208 {};
209 #endif
210
211 }
212
213 }} // namespace boost::hof
214
215 #ifdef _MSC_VER
216 #pragma warning(pop)
217 #endif
218
219 #endif
220