Ticket #2768: any.hpp

File any.hpp, 6.5 KB (added by nowake@…, 14 years ago)

boost::any that return unique type_info instance

Line 
1// See http://www.boost.org/libs/any for Documentation.
2
3#ifndef BOOST_ANY_INCLUDED
4#define BOOST_ANY_INCLUDED
5
6// what: variant type boost::any
7// who: contributed by Kevlin Henney,
8// with features contributed and bugs found by
9// Ed Brey, Mark Rodgers, Peter Dimov, and James Curran
10// when: July 2001
11// where: tested with BCC 5.5, MSVC 6.0, and g++ 2.95
12
13// Modified to implement unique type() by Nowake
14// and tested with MSVC 8.0
15
16#include <algorithm>
17#include <typeinfo>
18
19#include "boost/config.hpp"
20#include <boost/type_traits/remove_reference.hpp>
21#include <boost/type_traits/is_reference.hpp>
22#include <boost/throw_exception.hpp>
23#include <boost/static_assert.hpp>
24
25namespace boost
26{
27 class any
28 {
29 public: // structors
30
31 any()
32 : content(0)
33 {
34 }
35
36 template<typename ValueType>
37 any(const ValueType & value)
38 : content(new holder<ValueType>(value))
39 {
40 }
41
42 any(const any & other)
43 : content(other.content ? other.content->clone() : 0)
44 {
45 }
46
47 ~any()
48 {
49 delete content;
50 }
51
52 public: // modifiers
53
54 any & swap(any & rhs)
55 {
56 std::swap(content, rhs.content);
57 return *this;
58 }
59
60 template<typename ValueType>
61 any & operator=(const ValueType & rhs)
62 {
63 any(rhs).swap(*this);
64 return *this;
65 }
66
67 any & operator=(any rhs)
68 {
69 rhs.swap(*this);
70 return *this;
71 }
72
73 public: // queries
74
75 bool empty() const
76 {
77 return !content;
78 }
79
80
81 template<typename ValueType>
82 static const std::type_info& any::typeinfo()
83 {
84 static const std::type_info& r(typeid(ValueType));
85 return r;
86 }
87
88 const std::type_info & type() const
89 {
90 //return content ? content->type() : typeid(void);
91 return content ? content->type() : typeinfo<void>();
92 }
93
94#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
95 private: // types
96#else
97 public: // types (public so any_cast can be non-friend)
98#endif
99
100 class placeholder
101 {
102 public: // structors
103
104 virtual ~placeholder()
105 {
106 }
107
108 public: // queries
109
110 virtual const std::type_info & type() const = 0;
111
112 virtual placeholder * clone() const = 0;
113
114 };
115
116 template<typename ValueType>
117 class holder : public placeholder
118 {
119 public: // structors
120
121 holder(const ValueType & value)
122 : held(value)
123 {
124 }
125
126 public: // queries
127
128 virtual const std::type_info & type() const
129 {
130 //return typeid(ValueType);
131 return typeinfo<ValueType>();
132 }
133
134 virtual placeholder * clone() const
135 {
136 return new holder(held);
137 }
138
139 public: // representation
140
141 ValueType held;
142
143 private: // intentionally left unimplemented
144 holder & operator=(const holder &);
145 };
146
147#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
148
149 private: // representation
150
151 template<typename ValueType>
152 friend ValueType * any_cast(any *);
153
154 template<typename ValueType>
155 friend ValueType * unsafe_any_cast(any *);
156
157#else
158
159 public: // representation (public so any_cast can be non-friend)
160
161#endif
162
163 placeholder * content;
164
165 };
166
167 class bad_any_cast : public std::bad_cast
168 {
169 public:
170 virtual const char * what() const throw()
171 {
172 return "boost::bad_any_cast: "
173 "failed conversion using boost::any_cast";
174 }
175 };
176
177 template<typename ValueType>
178 ValueType * any_cast(any * operand)
179 {
180 return operand && operand->type() == typeid(ValueType)
181 ? &static_cast<any::holder<ValueType> *>(operand->content)->held
182 : 0;
183 }
184
185 template<typename ValueType>
186 inline const ValueType * any_cast(const any * operand)
187 {
188 return any_cast<ValueType>(const_cast<any *>(operand));
189 }
190
191 template<typename ValueType>
192 ValueType any_cast(any & operand)
193 {
194 typedef BOOST_DEDUCED_TYPENAME remove_reference<ValueType>::type nonref;
195
196#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
197 // If 'nonref' is still reference type, it means the user has not
198 // specialized 'remove_reference'.
199
200 // Please use BOOST_BROKEN_COMPILER_TYPE_TRAITS_SPECIALIZATION macro
201 // to generate specialization of remove_reference for your class
202 // See type traits library documentation for details
203 BOOST_STATIC_ASSERT(!is_reference<nonref>::value);
204#endif
205
206 nonref * result = any_cast<nonref>(&operand);
207 if(!result)
208 boost::throw_exception(bad_any_cast());
209 return *result;
210 }
211
212 template<typename ValueType>
213 inline ValueType any_cast(const any & operand)
214 {
215 typedef BOOST_DEDUCED_TYPENAME remove_reference<ValueType>::type nonref;
216
217#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
218 // The comment in the above version of 'any_cast' explains when this
219 // assert is fired and what to do.
220 BOOST_STATIC_ASSERT(!is_reference<nonref>::value);
221#endif
222
223 return any_cast<const nonref &>(const_cast<any &>(operand));
224 }
225
226 // Note: The "unsafe" versions of any_cast are not part of the
227 // public interface and may be removed at any time. They are
228 // required where we know what type is stored in the any and can't
229 // use typeid() comparison, e.g., when our types may travel across
230 // different shared libraries.
231 template<typename ValueType>
232 inline ValueType * unsafe_any_cast(any * operand)
233 {
234 return &static_cast<any::holder<ValueType> *>(operand->content)->held;
235 }
236
237 template<typename ValueType>
238 inline const ValueType * unsafe_any_cast(const any * operand)
239 {
240 return unsafe_any_cast<ValueType>(const_cast<any *>(operand));
241 }
242}
243
244// Copyright Kevlin Henney, 2000, 2001, 2002. All rights reserved.
245//
246// Distributed under the Boost Software License, Version 1.0. (See
247// accompanying file LICENSE_1_0.txt or copy at
248// http://www.boost.org/LICENSE_1_0.txt)
249
250#endif