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
62namespace boost { namespace hof {
63
64template<class T>
65struct alias_tag;
66
67template<class T, class Tag, class=void>
68struct has_tag
69: std::false_type
70{};
71
72template<class T, class Tag>
73struct 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
79namespace detail {
80
81template<class T>
82constexpr T& lvalue(T& x) noexcept
83{
84 return x;
85}
86
87template<class T>
88constexpr 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
100template<class T, class Tag=void>
101struct 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) \
108template<class Tag, class T, class... Ts> \
109constexpr auto alias_value(alias<T, Tag> ref a, Ts&&...) BOOST_HOF_RETURNS(move(a.value))
110BOOST_HOF_UNARY_PERFECT_FOREACH(BOOST_HOF_DETAIL_ALIAS_GET_VALUE)
111
112template<class T, class Tag>
113struct alias_tag<alias<T, Tag>>
114{ typedef Tag type; };
115
116
117template<class T, class Tag=void>
118struct 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) \
129template<class Tag, class T, class... Ts, class=typename std::enable_if<(BOOST_HOF_IS_CLASS(T))>::type> \
130constexpr T ref alias_value(alias_inherit<T, Tag> ref a, Ts&&...) BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT(move(a)) \
131{ \
132 return move(a); \
133}
134BOOST_HOF_UNARY_PERFECT_FOREACH(BOOST_HOF_DETAIL_ALIAS_INHERIT_GET_VALUE)
135
136template<class T, class Tag>
137struct alias_tag<alias_inherit<T, Tag>>
138{ typedef Tag type; };
139
140namespace detail {
141
142template<class T, class Tag>
143struct 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
157template<class T, class Tag>
158constexpr T alias_static_storage<T, Tag>::value;
159
160}
161
162template<class T, class Tag=void>
163struct alias_static
164{
165 template<class... Ts, BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(T, Ts...)>
166 constexpr alias_static(Ts&&...) noexcept
167 {}
168};
169
170template<class Tag, class T, class... Ts>
171constexpr const T& alias_value(const alias_static<T, Tag>&, Ts&&...) noexcept
172{
173 return detail::alias_static_storage<T, Tag>::value;
174}
175
176template<class T, class Tag>
177struct alias_tag<alias_static<T, Tag>>
178{ typedef Tag type; };
179
180namespace detail {
181
182template<class T, class Tag>
183struct 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
191template<class T, class Tag>
192struct 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
199template<class T, class Tag>
200struct 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

source code of boost/libs/hof/include/boost/hof/alias.hpp