]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // Boost.TypeErasure library |
2 | // | |
3 | // Copyright 2015 Steven Watanabe | |
4 | // | |
5 | // Distributed under the Boost Software License Version 1.0. (See | |
6 | // accompanying file LICENSE_1_0.txt or copy at | |
7 | // http://www.boost.org/LICENSE_1_0.txt) | |
8 | // | |
9 | // $Id$ | |
10 | ||
11 | #ifndef BOOST_TYPE_ERASURE_DYNAMIC_ANY_CAST_HPP_INCLUDED | |
12 | #define BOOST_TYPE_ERASURE_DYNAMIC_ANY_CAST_HPP_INCLUDED | |
13 | ||
14 | #include <boost/type_erasure/detail/normalize.hpp> | |
15 | #include <boost/type_erasure/binding_of.hpp> | |
16 | #include <boost/type_erasure/static_binding.hpp> | |
17 | #include <boost/type_erasure/dynamic_binding.hpp> | |
18 | #include <boost/type_erasure/concept_of.hpp> | |
19 | #include <boost/type_erasure/placeholder_of.hpp> | |
20 | #include <boost/type_erasure/any.hpp> | |
21 | #include <boost/type_erasure/binding.hpp> | |
22 | #include <boost/mpl/vector.hpp> | |
23 | #include <boost/mpl/set.hpp> | |
24 | #include <boost/mpl/fold.hpp> | |
25 | #include <boost/type_traits/add_const.hpp> | |
26 | #include <boost/type_traits/add_reference.hpp> | |
27 | #include <boost/type_traits/remove_const.hpp> | |
28 | #include <boost/type_traits/remove_reference.hpp> | |
29 | ||
30 | namespace boost { | |
31 | namespace type_erasure { | |
32 | ||
33 | namespace detail { | |
34 | ||
35 | template<class P, class P2, class Any> | |
36 | struct make_ref_placeholder; | |
37 | ||
38 | template<class P, class P2, class Any> | |
39 | struct make_ref_placeholder<P, P2, const Any&> { typedef const P& type; }; | |
40 | template<class P, class P2, class Any> | |
41 | struct make_ref_placeholder<P, P2, Any&> { typedef P& type; }; | |
42 | template<class P, class P2, class Any> | |
43 | struct make_ref_placeholder<P, P2&, const Any&> { typedef P& type; }; | |
44 | template<class P, class P2, class Any> | |
45 | struct make_ref_placeholder<P, P2&, Any&> { typedef P& type; }; | |
46 | template<class P, class P2, class Any> | |
47 | struct make_ref_placeholder<P, const P2&, const Any&> { typedef const P& type; }; | |
48 | template<class P, class P2, class Any> | |
49 | struct make_ref_placeholder<P, const P2&, Any&> { typedef const P& type; }; | |
50 | ||
51 | #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES | |
52 | template<class P, class P2, class Any> | |
53 | struct make_ref_placeholder { typedef P&& type; }; | |
54 | template<class P, class P2, class Any> | |
55 | struct make_ref_placeholder<P, P2&, Any> { typedef P& type; }; | |
56 | template<class P, class P2, class Any> | |
57 | struct make_ref_placeholder<P, const P2&, Any> { typedef const P& type; }; | |
58 | template<class P, class P2, class Any> | |
59 | struct make_ref_placeholder<P, P2&&, Any> { typedef P&& type; }; | |
60 | template<class P, class P2, class Any> | |
61 | struct make_ref_placeholder<P, P2&&, const Any&> { typedef const P& type; }; | |
62 | template<class P, class P2, class Any> | |
63 | struct make_ref_placeholder<P, P2&&, Any&> { typedef P& type; }; | |
64 | #endif | |
65 | ||
66 | template<class R, class Tag> | |
67 | struct make_result_placeholder_map | |
68 | { | |
69 | typedef ::boost::mpl::map< | |
70 | ::boost::mpl::pair< | |
71 | typename ::boost::remove_const< | |
72 | typename ::boost::remove_reference< | |
73 | typename ::boost::type_erasure::placeholder_of<R>::type | |
74 | >::type | |
75 | >::type, | |
76 | typename ::boost::remove_const< | |
77 | typename ::boost::remove_reference< | |
78 | Tag | |
79 | >::type | |
80 | >::type | |
81 | > | |
82 | > type; | |
83 | }; | |
84 | ||
85 | #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES | |
86 | template<class R, class Any, class Map> | |
87 | R dynamic_any_cast_impl(Any&& arg, const static_binding<Map>& map) | |
88 | #else | |
89 | template<class R, class Any, class Map> | |
90 | R dynamic_any_cast_impl(Any& arg, const static_binding<Map>& map) | |
91 | #endif | |
92 | { | |
93 | typedef typename ::boost::remove_const<typename ::boost::remove_reference<Any>::type>::type src_type; | |
94 | typedef typename ::boost::type_erasure::detail::normalize_concept< | |
95 | typename ::boost::type_erasure::concept_of<src_type>::type | |
96 | >::type normalized; | |
97 | typedef typename ::boost::mpl::fold< | |
98 | normalized, | |
99 | ::boost::mpl::set0<>, | |
100 | ::boost::type_erasure::detail::get_placeholders< | |
101 | ::boost::mpl::_2, | |
102 | ::boost::mpl::_1 | |
103 | > | |
104 | >::type placeholders; | |
105 | typedef ::boost::type_erasure::detail::substitution_map< ::boost::mpl::map0<> > identity_map; | |
106 | ::boost::type_erasure::dynamic_binding<placeholders> my_binding( | |
107 | ::boost::type_erasure::binding_of(arg), | |
108 | ::boost::type_erasure::make_binding<identity_map>()); | |
109 | typedef typename ::boost::remove_const< | |
110 | typename ::boost::remove_reference< | |
111 | typename ::boost::type_erasure::placeholder_of<R>::type | |
112 | >::type | |
113 | >::type result_placeholder; | |
114 | ::boost::type_erasure::binding< typename ::boost::type_erasure::concept_of<R>::type> new_binding( | |
115 | my_binding, | |
116 | map); | |
117 | typedef ::boost::type_erasure::any< | |
118 | typename ::boost::type_erasure::concept_of<R>::type, | |
119 | typename ::boost::type_erasure::detail::make_ref_placeholder< | |
120 | result_placeholder, | |
121 | typename ::boost::type_erasure::placeholder_of<src_type>::type, | |
122 | #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES | |
123 | Any | |
124 | #else | |
125 | Any& | |
126 | #endif | |
127 | >::type | |
128 | > result_ref_type; | |
129 | #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES | |
130 | return result_ref_type(std::forward<Any>(arg), new_binding); | |
131 | #else | |
132 | return result_ref_type(arg, new_binding); | |
133 | #endif | |
134 | } | |
135 | ||
136 | } | |
137 | ||
138 | #ifdef BOOST_TYPE_ERASURE_DOXYGEN | |
139 | ||
140 | /** | |
141 | * Downcasts or crosscasts an @ref any. | |
142 | * | |
143 | * \pre @c R and @c Any must both be specializations of @ref any. | |
144 | * \pre PlaceholderMap must be an MPL map with a key | |
145 | * for every non-deduced placeholder used by R. | |
146 | * The value associated with each key should | |
147 | * be the corresponding placeholder in Any. | |
148 | * \pre The concept of Any must include @ref typeid_, for every | |
149 | * @ref placeholder which is used by R. | |
150 | * | |
151 | * The single argument form can only be used when @c R uses | |
152 | * a single non-deduced placeholder. | |
153 | * | |
154 | * \throws bad_any_cast if the concepts used by R were | |
155 | * not previously registered via a call to | |
156 | * @ref register_binding. | |
157 | * | |
158 | * Example: | |
159 | * \code | |
160 | * // Assume that typeid_<>, copy_constructible<>, and incrementable<> | |
161 | * // have all been registered for int. | |
162 | * any<mpl::vector<typeid_<>, copy_constructible<> > > x(1); | |
163 | * typedef any< | |
164 | * mpl::vector< | |
165 | * typeid_<>, | |
166 | * copy_constructible<>, | |
167 | * incrementable<> | |
168 | * > | |
169 | * > incrementable_any; | |
170 | * auto y = dynamic_any_cast<incrementable_any>(x); | |
171 | * ++y; | |
172 | * assert(any_cast<int>(y) == 2); | |
173 | * \endcode | |
174 | */ | |
175 | template<class R, class Any> | |
176 | R dynamic_any_cast(Any&& arg); | |
177 | ||
178 | /** | |
179 | * \overload | |
180 | */ | |
181 | template<class R, class Any, class Map> | |
182 | R dynamic_any_cast(Any&& arg, const static_binding<Map>&); | |
183 | ||
184 | #else | |
185 | ||
186 | template<class R, class Concept, class Tag> | |
187 | R dynamic_any_cast(const any<Concept, Tag>& arg) | |
188 | { | |
189 | return ::boost::type_erasure::detail::dynamic_any_cast_impl<R>(arg, | |
190 | ::boost::type_erasure::make_binding<typename ::boost::type_erasure::detail::make_result_placeholder_map<R, Tag>::type>()); | |
191 | } | |
192 | ||
193 | template<class R, class Concept, class Tag> | |
194 | R dynamic_any_cast(any<Concept, Tag>& arg) | |
195 | { | |
196 | return ::boost::type_erasure::detail::dynamic_any_cast_impl<R>(arg, | |
197 | ::boost::type_erasure::make_binding<typename ::boost::type_erasure::detail::make_result_placeholder_map<R, Tag>::type>()); | |
198 | } | |
199 | ||
200 | #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES | |
201 | template<class R, class Concept, class Tag> | |
202 | R dynamic_any_cast(any<Concept, Tag>&& arg) | |
203 | { | |
204 | return ::boost::type_erasure::detail::dynamic_any_cast_impl<R>(::std::move(arg), | |
205 | ::boost::type_erasure::make_binding<typename ::boost::type_erasure::detail::make_result_placeholder_map<R, Tag>::type>()); | |
206 | } | |
207 | #endif | |
208 | ||
209 | template<class R, class Concept, class Tag, class Map> | |
210 | R dynamic_any_cast(const any<Concept, Tag>& arg, const static_binding<Map>& map) | |
211 | { | |
212 | return ::boost::type_erasure::detail::dynamic_any_cast_impl<R>(arg, map); | |
213 | } | |
214 | ||
215 | template<class R, class Concept, class Tag, class Map> | |
216 | R dynamic_any_cast(any<Concept, Tag>& arg, const static_binding<Map>& map) | |
217 | { | |
218 | return ::boost::type_erasure::detail::dynamic_any_cast_impl<R>(arg, map); | |
219 | } | |
220 | ||
221 | #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES | |
222 | template<class R, class Concept, class Tag, class Map> | |
223 | R dynamic_any_cast(any<Concept, Tag>&& arg, const static_binding<Map>& map) | |
224 | { | |
225 | return ::boost::type_erasure::detail::dynamic_any_cast_impl<R>(::std::move(arg), map); | |
226 | } | |
227 | #endif | |
228 | ||
229 | #endif | |
230 | ||
231 | } | |
232 | } | |
233 | ||
234 | #endif |