|
1 // Copyright (C) 2003, Fernando Luis Cacciola Carballal. |
|
2 // |
|
3 // Use, modification, and distribution is subject to the Boost Software |
|
4 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at |
|
5 // http://www.boost.org/LICENSE_1_0.txt) |
|
6 // |
|
7 // See http://www.boost.org/lib/optional for documentation. |
|
8 // |
|
9 // You are welcome to contact the author at: |
|
10 // fernando_cacciola@hotmail.com |
|
11 // |
|
12 #ifndef BOOST_OPTIONAL_OPTIONAL_FLC_19NOV2002_HPP |
|
13 #define BOOST_OPTIONAL_OPTIONAL_FLC_19NOV2002_HPP |
|
14 |
|
15 #include<new> |
|
16 #include<algorithm> |
|
17 |
|
18 #include "boost/config.hpp" |
|
19 #include "boost/assert.hpp" |
|
20 #include "boost/type.hpp" |
|
21 #include "boost/type_traits/alignment_of.hpp" |
|
22 #include "boost/type_traits/type_with_alignment.hpp" |
|
23 #include "boost/type_traits/remove_reference.hpp" |
|
24 #include "boost/type_traits/is_reference.hpp" |
|
25 #include "boost/mpl/if.hpp" |
|
26 #include "boost/mpl/bool.hpp" |
|
27 #include "boost/mpl/not.hpp" |
|
28 #include "boost/detail/reference_content.hpp" |
|
29 #include "boost/none.hpp" |
|
30 #include "boost/utility/compare_pointees.hpp" |
|
31 |
|
32 #include "boost/optional/optional_fwd.hpp" |
|
33 |
|
34 #if BOOST_WORKAROUND(BOOST_MSVC, == 1200) |
|
35 // VC6.0 has the following bug: |
|
36 // When a templated assignment operator exist, an implicit conversion |
|
37 // constructing an optional<T> is used when assigment of the form: |
|
38 // optional<T> opt ; opt = T(...); |
|
39 // is compiled. |
|
40 // However, optional's ctor is _explicit_ and the assignemt shouldn't compile. |
|
41 // Therefore, for VC6.0 templated assignment is disabled. |
|
42 // |
|
43 #define BOOST_OPTIONAL_NO_CONVERTING_ASSIGNMENT |
|
44 #endif |
|
45 |
|
46 #if BOOST_WORKAROUND(BOOST_MSVC, == 1300) |
|
47 // VC7.0 has the following bug: |
|
48 // When both a non-template and a template copy-ctor exist |
|
49 // and the templated version is made 'explicit', the explicit is also |
|
50 // given to the non-templated version, making the class non-implicitely-copyable. |
|
51 // |
|
52 #define BOOST_OPTIONAL_NO_CONVERTING_COPY_CTOR |
|
53 #endif |
|
54 |
|
55 #if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) || BOOST_WORKAROUND(BOOST_INTEL_CXX_VERSION,<=700) |
|
56 // AFAICT only VC7.1 correctly resolves the overload set |
|
57 // that includes the in-place factory taking functions, |
|
58 // so for the other VC versions, in-place factory support |
|
59 // is disabled |
|
60 #define BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT |
|
61 #endif |
|
62 |
|
63 #if BOOST_WORKAROUND(__BORLANDC__, <= 0x551) |
|
64 // BCB (5.5.1) cannot parse the nested template struct in an inplace factory. |
|
65 #define BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT |
|
66 #endif |
|
67 |
|
68 #if !defined(BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT) \ |
|
69 && BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x581) ) |
|
70 // BCB (up to 5.64) has the following bug: |
|
71 // If there is a member function/operator template of the form |
|
72 // template<class Expr> mfunc( Expr expr ) ; |
|
73 // some calls are resolved to this even if there are other better matches. |
|
74 // The effect of this bug is that calls to converting ctors and assignments |
|
75 // are incrorrectly sink to this general catch-all member function template as shown above. |
|
76 #define BOOST_OPTIONAL_WEAK_OVERLOAD_RESOLUTION |
|
77 #endif |
|
78 |
|
79 // Daniel Wallin discovered that bind/apply.hpp badly interacts with the apply<> |
|
80 // member template of a factory as used in the optional<> implementation. |
|
81 // He proposed this simple fix which is to move the call to apply<> outside |
|
82 // namespace boost. |
|
83 namespace boost_optional_detail |
|
84 { |
|
85 template <class T, class Factory> |
|
86 void construct(Factory const& factory, void* address) |
|
87 { |
|
88 factory.BOOST_NESTED_TEMPLATE apply<T>(address); |
|
89 } |
|
90 } |
|
91 |
|
92 |
|
93 namespace boost { |
|
94 |
|
95 class in_place_factory_base ; |
|
96 class typed_in_place_factory_base ; |
|
97 |
|
98 namespace optional_detail { |
|
99 |
|
100 // This local class is used instead of that in "aligned_storage.hpp" |
|
101 // because I've found the 'official' class to ICE BCB5.5 |
|
102 // when some types are used with optional<> |
|
103 // (due to sizeof() passed down as a non-type template parameter) |
|
104 template <class T> |
|
105 class aligned_storage |
|
106 { |
|
107 // Borland ICEs if unnamed unions are used for this! |
|
108 union dummy_u |
|
109 { |
|
110 char data[ sizeof(T) ]; |
|
111 BOOST_DEDUCED_TYPENAME type_with_alignment< |
|
112 ::boost::alignment_of<T>::value >::type aligner_; |
|
113 } dummy_ ; |
|
114 |
|
115 public: |
|
116 |
|
117 void const* address() const { return &dummy_.data[0]; } |
|
118 void * address() { return &dummy_.data[0]; } |
|
119 } ; |
|
120 |
|
121 template<class T> |
|
122 struct types_when_isnt_ref |
|
123 { |
|
124 typedef T const& reference_const_type ; |
|
125 typedef T & reference_type ; |
|
126 typedef T const* pointer_const_type ; |
|
127 typedef T * pointer_type ; |
|
128 typedef T const& argument_type ; |
|
129 } ; |
|
130 template<class T> |
|
131 struct types_when_is_ref |
|
132 { |
|
133 typedef BOOST_DEDUCED_TYPENAME remove_reference<T>::type raw_type ; |
|
134 |
|
135 typedef raw_type& reference_const_type ; |
|
136 typedef raw_type& reference_type ; |
|
137 typedef raw_type* pointer_const_type ; |
|
138 typedef raw_type* pointer_type ; |
|
139 typedef raw_type& argument_type ; |
|
140 } ; |
|
141 |
|
142 struct optional_tag {} ; |
|
143 |
|
144 template<class T> |
|
145 class optional_base : public optional_tag |
|
146 { |
|
147 private : |
|
148 |
|
149 typedef |
|
150 #if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) |
|
151 BOOST_DEDUCED_TYPENAME |
|
152 #endif |
|
153 ::boost::detail::make_reference_content<T>::type internal_type ; |
|
154 |
|
155 typedef aligned_storage<internal_type> storage_type ; |
|
156 |
|
157 typedef types_when_isnt_ref<T> types_when_not_ref ; |
|
158 typedef types_when_is_ref<T> types_when_ref ; |
|
159 |
|
160 typedef optional_base<T> this_type ; |
|
161 |
|
162 protected : |
|
163 |
|
164 typedef T value_type ; |
|
165 |
|
166 typedef mpl::true_ is_reference_tag ; |
|
167 typedef mpl::false_ is_not_reference_tag ; |
|
168 |
|
169 typedef BOOST_DEDUCED_TYPENAME is_reference<T>::type is_reference_predicate ; |
|
170 |
|
171 typedef BOOST_DEDUCED_TYPENAME mpl::if_<is_reference_predicate,types_when_ref,types_when_not_ref>::type types ; |
|
172 |
|
173 typedef bool (this_type::*unspecified_bool_type)() const; |
|
174 |
|
175 typedef BOOST_DEDUCED_TYPENAME types::reference_type reference_type ; |
|
176 typedef BOOST_DEDUCED_TYPENAME types::reference_const_type reference_const_type ; |
|
177 typedef BOOST_DEDUCED_TYPENAME types::pointer_type pointer_type ; |
|
178 typedef BOOST_DEDUCED_TYPENAME types::pointer_const_type pointer_const_type ; |
|
179 typedef BOOST_DEDUCED_TYPENAME types::argument_type argument_type ; |
|
180 |
|
181 // Creates an optional<T> uninitialized. |
|
182 // No-throw |
|
183 optional_base() |
|
184 : |
|
185 m_initialized(false) {} |
|
186 |
|
187 // Creates an optional<T> uninitialized. |
|
188 // No-throw |
|
189 optional_base ( none_t ) |
|
190 : |
|
191 m_initialized(false) {} |
|
192 |
|
193 // Creates an optional<T> initialized with 'val'. |
|
194 // Can throw if T::T(T const&) does |
|
195 optional_base ( argument_type val ) |
|
196 : |
|
197 m_initialized(false) |
|
198 { |
|
199 construct(val); |
|
200 } |
|
201 |
|
202 // Creates an optional<T> initialized with 'val' IFF cond is true, otherwise creates an uninitialzed optional<T>. |
|
203 // Can throw if T::T(T const&) does |
|
204 optional_base ( bool cond, argument_type val ) |
|
205 : |
|
206 m_initialized(false) |
|
207 { |
|
208 if ( cond ) |
|
209 construct(val); |
|
210 } |
|
211 |
|
212 // Creates a deep copy of another optional<T> |
|
213 // Can throw if T::T(T const&) does |
|
214 optional_base ( optional_base const& rhs ) |
|
215 : |
|
216 m_initialized(false) |
|
217 { |
|
218 if ( rhs.is_initialized() ) |
|
219 construct(rhs.get_impl()); |
|
220 } |
|
221 |
|
222 |
|
223 // This is used for both converting and in-place constructions. |
|
224 // Derived classes use the 'tag' to select the appropriate |
|
225 // implementation (the correct 'construct()' overload) |
|
226 template<class Expr> |
|
227 explicit optional_base ( Expr const& expr, Expr const* tag ) |
|
228 : |
|
229 m_initialized(false) |
|
230 { |
|
231 construct(expr,tag); |
|
232 } |
|
233 |
|
234 |
|
235 |
|
236 // No-throw (assuming T::~T() doesn't) |
|
237 ~optional_base() { destroy() ; } |
|
238 |
|
239 // Assigns from another optional<T> (deep-copies the rhs value) |
|
240 void assign ( optional_base const& rhs ) |
|
241 { |
|
242 if (is_initialized()) |
|
243 { |
|
244 if ( rhs.is_initialized() ) |
|
245 assign_value(rhs.get_impl(), is_reference_predicate() ); |
|
246 else destroy(); |
|
247 } |
|
248 else |
|
249 { |
|
250 if ( rhs.is_initialized() ) |
|
251 construct(rhs.get_impl()); |
|
252 } |
|
253 } |
|
254 |
|
255 // Assigns from another _convertible_ optional<U> (deep-copies the rhs value) |
|
256 template<class U> |
|
257 void assign ( optional<U> const& rhs ) |
|
258 { |
|
259 if (is_initialized()) |
|
260 { |
|
261 if ( rhs.is_initialized() ) |
|
262 assign_value(static_cast<value_type>(rhs.get()), is_reference_predicate() ); |
|
263 else destroy(); |
|
264 } |
|
265 else |
|
266 { |
|
267 if ( rhs.is_initialized() ) |
|
268 construct(static_cast<value_type>(rhs.get())); |
|
269 } |
|
270 } |
|
271 |
|
272 // Assigns from a T (deep-copies the rhs value) |
|
273 void assign ( argument_type val ) |
|
274 { |
|
275 if (is_initialized()) |
|
276 assign_value(val, is_reference_predicate() ); |
|
277 else construct(val); |
|
278 } |
|
279 |
|
280 // Assigns from "none", destroying the current value, if any, leaving this UNINITIALIZED |
|
281 // No-throw (assuming T::~T() doesn't) |
|
282 void assign ( none_t ) { destroy(); } |
|
283 |
|
284 #ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT |
|
285 template<class Expr> |
|
286 void assign_expr ( Expr const& expr, Expr const* tag ) |
|
287 { |
|
288 if (is_initialized()) |
|
289 assign_expr_to_initialized(expr,tag); |
|
290 else construct(expr,tag); |
|
291 } |
|
292 #endif |
|
293 |
|
294 public : |
|
295 |
|
296 // Destroys the current value, if any, leaving this UNINITIALIZED |
|
297 // No-throw (assuming T::~T() doesn't) |
|
298 void reset() { destroy(); } |
|
299 |
|
300 // Replaces the current value -if any- with 'val' |
|
301 void reset ( argument_type val ) { assign(val); } |
|
302 |
|
303 // Returns a pointer to the value if this is initialized, otherwise, |
|
304 // returns NULL. |
|
305 // No-throw |
|
306 pointer_const_type get_ptr() const { return m_initialized ? get_ptr_impl() : 0 ; } |
|
307 pointer_type get_ptr() { return m_initialized ? get_ptr_impl() : 0 ; } |
|
308 |
|
309 bool is_initialized() const { return m_initialized ; } |
|
310 |
|
311 protected : |
|
312 |
|
313 void construct ( argument_type val ) |
|
314 { |
|
315 new (m_storage.address()) internal_type(val) ; |
|
316 m_initialized = true ; |
|
317 } |
|
318 |
|
319 #ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT |
|
320 // Constructs in-place using the given factory |
|
321 template<class Expr> |
|
322 void construct ( Expr const& factory, in_place_factory_base const* ) |
|
323 { |
|
324 BOOST_STATIC_ASSERT ( ::boost::mpl::not_<is_reference_predicate>::value ) ; |
|
325 boost_optional_detail::construct<value_type>(factory, m_storage.address()); |
|
326 m_initialized = true ; |
|
327 } |
|
328 |
|
329 // Constructs in-place using the given typed factory |
|
330 template<class Expr> |
|
331 void construct ( Expr const& factory, typed_in_place_factory_base const* ) |
|
332 { |
|
333 BOOST_STATIC_ASSERT ( ::boost::mpl::not_<is_reference_predicate>::value ) ; |
|
334 factory.apply(m_storage.address()) ; |
|
335 m_initialized = true ; |
|
336 } |
|
337 |
|
338 template<class Expr> |
|
339 void assign_expr_to_initialized ( Expr const& factory, in_place_factory_base const* tag ) |
|
340 { |
|
341 destroy(); |
|
342 construct(factory,tag); |
|
343 } |
|
344 |
|
345 // Constructs in-place using the given typed factory |
|
346 template<class Expr> |
|
347 void assign_expr_to_initialized ( Expr const& factory, typed_in_place_factory_base const* tag ) |
|
348 { |
|
349 destroy(); |
|
350 construct(factory,tag); |
|
351 } |
|
352 #endif |
|
353 |
|
354 // Constructs using any expression implicitely convertible to the single argument |
|
355 // of a one-argument T constructor. |
|
356 // Converting constructions of optional<T> from optional<U> uses this function with |
|
357 // 'Expr' being of type 'U' and relying on a converting constructor of T from U. |
|
358 template<class Expr> |
|
359 void construct ( Expr const& expr, void const* ) |
|
360 { |
|
361 new (m_storage.address()) internal_type(expr) ; |
|
362 m_initialized = true ; |
|
363 } |
|
364 |
|
365 // Assigns using a form any expression implicitely convertible to the single argument |
|
366 // of a T's assignment operator. |
|
367 // Converting assignments of optional<T> from optional<U> uses this function with |
|
368 // 'Expr' being of type 'U' and relying on a converting assignment of T from U. |
|
369 template<class Expr> |
|
370 void assign_expr_to_initialized ( Expr const& expr, void const* ) |
|
371 { |
|
372 assign_value(expr, is_reference_predicate()); |
|
373 } |
|
374 |
|
375 #ifdef BOOST_OPTIONAL_WEAK_OVERLOAD_RESOLUTION |
|
376 // BCB5.64 (and probably lower versions) workaround. |
|
377 // The in-place factories are supported by means of catch-all constructors |
|
378 // and assignment operators (the functions are parameterized in terms of |
|
379 // an arbitrary 'Expr' type) |
|
380 // This compiler incorrectly resolves the overload set and sinks optional<T> and optional<U> |
|
381 // to the 'Expr'-taking functions even though explicit overloads are present for them. |
|
382 // Thus, the following overload is needed to properly handle the case when the 'lhs' |
|
383 // is another optional. |
|
384 // |
|
385 // For VC<=70 compilers this workaround dosen't work becasue the comnpiler issues and error |
|
386 // instead of choosing the wrong overload |
|
387 // |
|
388 // Notice that 'Expr' will be optional<T> or optional<U> (but not optional_base<..>) |
|
389 template<class Expr> |
|
390 void construct ( Expr const& expr, optional_tag const* ) |
|
391 { |
|
392 if ( expr.is_initialized() ) |
|
393 { |
|
394 // An exception can be thrown here. |
|
395 // It it happens, THIS will be left uninitialized. |
|
396 new (m_storage.address()) internal_type(expr.get()) ; |
|
397 m_initialized = true ; |
|
398 } |
|
399 } |
|
400 #endif |
|
401 |
|
402 void assign_value ( argument_type val, is_not_reference_tag ) { get_impl() = val; } |
|
403 void assign_value ( argument_type val, is_reference_tag ) { construct(val); } |
|
404 |
|
405 void destroy() |
|
406 { |
|
407 if ( m_initialized ) |
|
408 destroy_impl(is_reference_predicate()) ; |
|
409 } |
|
410 |
|
411 unspecified_bool_type safe_bool() const { return m_initialized ? &this_type::is_initialized : 0 ; } |
|
412 |
|
413 reference_const_type get_impl() const { return dereference(get_object(), is_reference_predicate() ) ; } |
|
414 reference_type get_impl() { return dereference(get_object(), is_reference_predicate() ) ; } |
|
415 |
|
416 pointer_const_type get_ptr_impl() const { return cast_ptr(get_object(), is_reference_predicate() ) ; } |
|
417 pointer_type get_ptr_impl() { return cast_ptr(get_object(), is_reference_predicate() ) ; } |
|
418 |
|
419 private : |
|
420 |
|
421 // internal_type can be either T or reference_content<T> |
|
422 internal_type const* get_object() const { return static_cast<internal_type const*>(m_storage.address()); } |
|
423 internal_type * get_object() { return static_cast<internal_type *> (m_storage.address()); } |
|
424 |
|
425 // reference_content<T> lacks an implicit conversion to T&, so the following is needed to obtain a proper reference. |
|
426 reference_const_type dereference( internal_type const* p, is_not_reference_tag ) const { return *p ; } |
|
427 reference_type dereference( internal_type* p, is_not_reference_tag ) { return *p ; } |
|
428 reference_const_type dereference( internal_type const* p, is_reference_tag ) const { return p->get() ; } |
|
429 reference_type dereference( internal_type* p, is_reference_tag ) { return p->get() ; } |
|
430 |
|
431 #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x581)) |
|
432 void destroy_impl ( is_not_reference_tag ) { get_ptr_impl()->internal_type::~internal_type() ; m_initialized = false ; } |
|
433 #else |
|
434 void destroy_impl ( is_not_reference_tag ) { get_ptr_impl()->T::~T() ; m_initialized = false ; } |
|
435 #endif |
|
436 |
|
437 void destroy_impl ( is_reference_tag ) { m_initialized = false ; } |
|
438 |
|
439 // If T is of reference type, trying to get a pointer to the held value must result in a compile-time error. |
|
440 // Decent compilers should disallow conversions from reference_content<T>* to T*, but just in case, |
|
441 // the following olverloads are used to filter out the case and guarantee an error in case of T being a reference. |
|
442 pointer_const_type cast_ptr( internal_type const* p, is_not_reference_tag ) const { return p ; } |
|
443 pointer_type cast_ptr( internal_type * p, is_not_reference_tag ) { return p ; } |
|
444 pointer_const_type cast_ptr( internal_type const* p, is_reference_tag ) const { return &p->get() ; } |
|
445 pointer_type cast_ptr( internal_type * p, is_reference_tag ) { return &p->get() ; } |
|
446 |
|
447 bool m_initialized ; |
|
448 storage_type m_storage ; |
|
449 } ; |
|
450 |
|
451 } // namespace optional_detail |
|
452 |
|
453 template<class T> |
|
454 class optional : public optional_detail::optional_base<T> |
|
455 { |
|
456 typedef optional_detail::optional_base<T> base ; |
|
457 |
|
458 typedef BOOST_DEDUCED_TYPENAME base::unspecified_bool_type unspecified_bool_type ; |
|
459 |
|
460 public : |
|
461 |
|
462 typedef optional<T> this_type ; |
|
463 |
|
464 typedef BOOST_DEDUCED_TYPENAME base::value_type value_type ; |
|
465 typedef BOOST_DEDUCED_TYPENAME base::reference_type reference_type ; |
|
466 typedef BOOST_DEDUCED_TYPENAME base::reference_const_type reference_const_type ; |
|
467 typedef BOOST_DEDUCED_TYPENAME base::pointer_type pointer_type ; |
|
468 typedef BOOST_DEDUCED_TYPENAME base::pointer_const_type pointer_const_type ; |
|
469 typedef BOOST_DEDUCED_TYPENAME base::argument_type argument_type ; |
|
470 |
|
471 // Creates an optional<T> uninitialized. |
|
472 // No-throw |
|
473 optional() : base() {} |
|
474 |
|
475 // Creates an optional<T> uninitialized. |
|
476 // No-throw |
|
477 optional( none_t none_ ) : base(none_) {} |
|
478 |
|
479 // Creates an optional<T> initialized with 'val'. |
|
480 // Can throw if T::T(T const&) does |
|
481 optional ( argument_type val ) : base(val) {} |
|
482 |
|
483 // Creates an optional<T> initialized with 'val' IFF cond is true, otherwise creates an uninitialized optional. |
|
484 // Can throw if T::T(T const&) does |
|
485 optional ( bool cond, argument_type val ) : base(cond,val) {} |
|
486 |
|
487 #ifndef BOOST_OPTIONAL_NO_CONVERTING_COPY_CTOR |
|
488 // NOTE: MSVC needs templated versions first |
|
489 |
|
490 // Creates a deep copy of another convertible optional<U> |
|
491 // Requires a valid conversion from U to T. |
|
492 // Can throw if T::T(U const&) does |
|
493 template<class U> |
|
494 explicit optional ( optional<U> const& rhs ) |
|
495 : |
|
496 base() |
|
497 { |
|
498 if ( rhs.is_initialized() ) |
|
499 this->construct(rhs.get()); |
|
500 } |
|
501 #endif |
|
502 |
|
503 #ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT |
|
504 // Creates an optional<T> with an expression which can be either |
|
505 // (a) An instance of InPlaceFactory (i.e. in_place(a,b,...,n); |
|
506 // (b) An instance of TypedInPlaceFactory ( i.e. in_place<T>(a,b,...,n); |
|
507 // (c) Any expression implicitely convertible to the single type |
|
508 // of a one-argument T's constructor. |
|
509 // (d*) Weak compilers (BCB) might also resolved Expr as optional<T> and optional<U> |
|
510 // even though explicit overloads are present for these. |
|
511 // Depending on the above some T ctor is called. |
|
512 // Can throw is the resolved T ctor throws. |
|
513 template<class Expr> |
|
514 explicit optional ( Expr const& expr ) : base(expr,&expr) {} |
|
515 #endif |
|
516 |
|
517 // Creates a deep copy of another optional<T> |
|
518 // Can throw if T::T(T const&) does |
|
519 optional ( optional const& rhs ) : base(rhs) {} |
|
520 |
|
521 // No-throw (assuming T::~T() doesn't) |
|
522 ~optional() {} |
|
523 |
|
524 #if !defined(BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT) && !defined(BOOST_OPTIONAL_WEAK_OVERLOAD_RESOLUTION) |
|
525 // Assigns from an expression. See corresponding constructor. |
|
526 // Basic Guarantee: If the resolved T ctor throws, this is left UNINITIALIZED |
|
527 template<class Expr> |
|
528 optional& operator= ( Expr expr ) |
|
529 { |
|
530 this->assign_expr(expr,&expr); |
|
531 return *this ; |
|
532 } |
|
533 #endif |
|
534 |
|
535 |
|
536 #ifndef BOOST_OPTIONAL_NO_CONVERTING_ASSIGNMENT |
|
537 // Assigns from another convertible optional<U> (converts && deep-copies the rhs value) |
|
538 // Requires a valid conversion from U to T. |
|
539 // Basic Guarantee: If T::T( U const& ) throws, this is left UNINITIALIZED |
|
540 template<class U> |
|
541 optional& operator= ( optional<U> const& rhs ) |
|
542 { |
|
543 this->assign(rhs); |
|
544 return *this ; |
|
545 } |
|
546 #endif |
|
547 |
|
548 // Assigns from another optional<T> (deep-copies the rhs value) |
|
549 // Basic Guarantee: If T::T( T const& ) throws, this is left UNINITIALIZED |
|
550 // (NOTE: On BCB, this operator is not actually called and left is left UNMODIFIED in case of a throw) |
|
551 optional& operator= ( optional const& rhs ) |
|
552 { |
|
553 this->assign( rhs ) ; |
|
554 return *this ; |
|
555 } |
|
556 |
|
557 // Assigns from a T (deep-copies the rhs value) |
|
558 // Basic Guarantee: If T::( T const& ) throws, this is left UNINITIALIZED |
|
559 optional& operator= ( argument_type val ) |
|
560 { |
|
561 this->assign( val ) ; |
|
562 return *this ; |
|
563 } |
|
564 |
|
565 // Assigns from a "none" |
|
566 // Which destroys the current value, if any, leaving this UNINITIALIZED |
|
567 // No-throw (assuming T::~T() doesn't) |
|
568 optional& operator= ( none_t none_ ) |
|
569 { |
|
570 this->assign( none_ ) ; |
|
571 return *this ; |
|
572 } |
|
573 |
|
574 // Returns a reference to the value if this is initialized, otherwise, |
|
575 // the behaviour is UNDEFINED |
|
576 // No-throw |
|
577 reference_const_type get() const { BOOST_ASSERT(this->is_initialized()) ; return this->get_impl(); } |
|
578 reference_type get() { BOOST_ASSERT(this->is_initialized()) ; return this->get_impl(); } |
|
579 |
|
580 // Returns a copy of the value if this is initialized, 'v' otherwise |
|
581 reference_const_type get_value_or ( reference_const_type v ) const { return this->is_initialized() ? get() : v ; } |
|
582 reference_type get_value_or ( reference_type v ) { return this->is_initialized() ? get() : v ; } |
|
583 |
|
584 // Returns a pointer to the value if this is initialized, otherwise, |
|
585 // the behaviour is UNDEFINED |
|
586 // No-throw |
|
587 pointer_const_type operator->() const { BOOST_ASSERT(this->is_initialized()) ; return this->get_ptr_impl() ; } |
|
588 pointer_type operator->() { BOOST_ASSERT(this->is_initialized()) ; return this->get_ptr_impl() ; } |
|
589 |
|
590 // Returns a reference to the value if this is initialized, otherwise, |
|
591 // the behaviour is UNDEFINED |
|
592 // No-throw |
|
593 reference_const_type operator *() const { return this->get() ; } |
|
594 reference_type operator *() { return this->get() ; } |
|
595 |
|
596 // implicit conversion to "bool" |
|
597 // No-throw |
|
598 operator unspecified_bool_type() const { return this->safe_bool() ; } |
|
599 |
|
600 // This is provided for those compilers which don't like the conversion to bool |
|
601 // on some contexts. |
|
602 bool operator!() const { return !this->is_initialized() ; } |
|
603 } ; |
|
604 |
|
605 // Returns optional<T>(v) |
|
606 template<class T> |
|
607 inline |
|
608 optional<T> make_optional ( T const& v ) |
|
609 { |
|
610 return optional<T>(v); |
|
611 } |
|
612 |
|
613 // Returns optional<T>(cond,v) |
|
614 template<class T> |
|
615 inline |
|
616 optional<T> make_optional ( bool cond, T const& v ) |
|
617 { |
|
618 return optional<T>(cond,v); |
|
619 } |
|
620 |
|
621 // Returns a reference to the value if this is initialized, otherwise, the behaviour is UNDEFINED. |
|
622 // No-throw |
|
623 template<class T> |
|
624 inline |
|
625 BOOST_DEDUCED_TYPENAME optional<T>::reference_const_type |
|
626 get ( optional<T> const& opt ) |
|
627 { |
|
628 return opt.get() ; |
|
629 } |
|
630 |
|
631 template<class T> |
|
632 inline |
|
633 BOOST_DEDUCED_TYPENAME optional<T>::reference_type |
|
634 get ( optional<T>& opt ) |
|
635 { |
|
636 return opt.get() ; |
|
637 } |
|
638 |
|
639 // Returns a pointer to the value if this is initialized, otherwise, returns NULL. |
|
640 // No-throw |
|
641 template<class T> |
|
642 inline |
|
643 BOOST_DEDUCED_TYPENAME optional<T>::pointer_const_type |
|
644 get ( optional<T> const* opt ) |
|
645 { |
|
646 return opt->get_ptr() ; |
|
647 } |
|
648 |
|
649 template<class T> |
|
650 inline |
|
651 BOOST_DEDUCED_TYPENAME optional<T>::pointer_type |
|
652 get ( optional<T>* opt ) |
|
653 { |
|
654 return opt->get_ptr() ; |
|
655 } |
|
656 |
|
657 // Returns a reference to the value if this is initialized, otherwise, the behaviour is UNDEFINED. |
|
658 // No-throw |
|
659 template<class T> |
|
660 inline |
|
661 BOOST_DEDUCED_TYPENAME optional<T>::reference_const_type |
|
662 get_optional_value_or ( optional<T> const& opt, BOOST_DEDUCED_TYPENAME optional<T>::reference_const_type v ) |
|
663 { |
|
664 return opt.get_value_or(v) ; |
|
665 } |
|
666 |
|
667 template<class T> |
|
668 inline |
|
669 BOOST_DEDUCED_TYPENAME optional<T>::reference_type |
|
670 get_optional_value_or ( optional<T>& opt, BOOST_DEDUCED_TYPENAME optional<T>::reference_type v ) |
|
671 { |
|
672 return opt.get_value_or(v) ; |
|
673 } |
|
674 |
|
675 // Returns a pointer to the value if this is initialized, otherwise, returns NULL. |
|
676 // No-throw |
|
677 template<class T> |
|
678 inline |
|
679 BOOST_DEDUCED_TYPENAME optional<T>::pointer_const_type |
|
680 get_pointer ( optional<T> const& opt ) |
|
681 { |
|
682 return opt.get_ptr() ; |
|
683 } |
|
684 |
|
685 template<class T> |
|
686 inline |
|
687 BOOST_DEDUCED_TYPENAME optional<T>::pointer_type |
|
688 get_pointer ( optional<T>& opt ) |
|
689 { |
|
690 return opt.get_ptr() ; |
|
691 } |
|
692 |
|
693 // optional's relational operators ( ==, !=, <, >, <=, >= ) have deep-semantics (compare values). |
|
694 // WARNING: This is UNLIKE pointers. Use equal_pointees()/less_pointess() in generic code instead. |
|
695 |
|
696 |
|
697 // |
|
698 // optional<T> vs optional<T> cases |
|
699 // |
|
700 |
|
701 template<class T> |
|
702 inline |
|
703 bool operator == ( optional<T> const& x, optional<T> const& y ) |
|
704 { return equal_pointees(x,y); } |
|
705 |
|
706 template<class T> |
|
707 inline |
|
708 bool operator < ( optional<T> const& x, optional<T> const& y ) |
|
709 { return less_pointees(x,y); } |
|
710 |
|
711 template<class T> |
|
712 inline |
|
713 bool operator != ( optional<T> const& x, optional<T> const& y ) |
|
714 { return !( x == y ) ; } |
|
715 |
|
716 template<class T> |
|
717 inline |
|
718 bool operator > ( optional<T> const& x, optional<T> const& y ) |
|
719 { return y < x ; } |
|
720 |
|
721 template<class T> |
|
722 inline |
|
723 bool operator <= ( optional<T> const& x, optional<T> const& y ) |
|
724 { return !( y < x ) ; } |
|
725 |
|
726 template<class T> |
|
727 inline |
|
728 bool operator >= ( optional<T> const& x, optional<T> const& y ) |
|
729 { return !( x < y ) ; } |
|
730 |
|
731 |
|
732 // |
|
733 // optional<T> vs T cases |
|
734 // |
|
735 template<class T> |
|
736 inline |
|
737 bool operator == ( optional<T> const& x, T const& y ) |
|
738 { return equal_pointees(x, optional<T>(y)); } |
|
739 |
|
740 template<class T> |
|
741 inline |
|
742 bool operator < ( optional<T> const& x, T const& y ) |
|
743 { return less_pointees(x, optional<T>(y)); } |
|
744 |
|
745 template<class T> |
|
746 inline |
|
747 bool operator != ( optional<T> const& x, T const& y ) |
|
748 { return !( x == y ) ; } |
|
749 |
|
750 template<class T> |
|
751 inline |
|
752 bool operator > ( optional<T> const& x, T const& y ) |
|
753 { return y < x ; } |
|
754 |
|
755 template<class T> |
|
756 inline |
|
757 bool operator <= ( optional<T> const& x, T const& y ) |
|
758 { return !( y < x ) ; } |
|
759 |
|
760 template<class T> |
|
761 inline |
|
762 bool operator >= ( optional<T> const& x, T const& y ) |
|
763 { return !( x < y ) ; } |
|
764 |
|
765 // |
|
766 // T vs optional<T> cases |
|
767 // |
|
768 |
|
769 template<class T> |
|
770 inline |
|
771 bool operator == ( T const& x, optional<T> const& y ) |
|
772 { return equal_pointees( optional<T>(x), y ); } |
|
773 |
|
774 template<class T> |
|
775 inline |
|
776 bool operator < ( T const& x, optional<T> const& y ) |
|
777 { return less_pointees( optional<T>(x), y ); } |
|
778 |
|
779 template<class T> |
|
780 inline |
|
781 bool operator != ( T const& x, optional<T> const& y ) |
|
782 { return !( x == y ) ; } |
|
783 |
|
784 template<class T> |
|
785 inline |
|
786 bool operator > ( T const& x, optional<T> const& y ) |
|
787 { return y < x ; } |
|
788 |
|
789 template<class T> |
|
790 inline |
|
791 bool operator <= ( T const& x, optional<T> const& y ) |
|
792 { return !( y < x ) ; } |
|
793 |
|
794 template<class T> |
|
795 inline |
|
796 bool operator >= ( T const& x, optional<T> const& y ) |
|
797 { return !( x < y ) ; } |
|
798 |
|
799 |
|
800 // |
|
801 // optional<T> vs none cases |
|
802 // |
|
803 |
|
804 template<class T> |
|
805 inline |
|
806 bool operator == ( optional<T> const& x, none_t ) |
|
807 { return equal_pointees(x, optional<T>() ); } |
|
808 |
|
809 template<class T> |
|
810 inline |
|
811 bool operator < ( optional<T> const& x, none_t ) |
|
812 { return less_pointees(x,optional<T>() ); } |
|
813 |
|
814 template<class T> |
|
815 inline |
|
816 bool operator != ( optional<T> const& x, none_t y ) |
|
817 { return !( x == y ) ; } |
|
818 |
|
819 template<class T> |
|
820 inline |
|
821 bool operator > ( optional<T> const& x, none_t y ) |
|
822 { return y < x ; } |
|
823 |
|
824 template<class T> |
|
825 inline |
|
826 bool operator <= ( optional<T> const& x, none_t y ) |
|
827 { return !( y < x ) ; } |
|
828 |
|
829 template<class T> |
|
830 inline |
|
831 bool operator >= ( optional<T> const& x, none_t y ) |
|
832 { return !( x < y ) ; } |
|
833 |
|
834 // |
|
835 // none vs optional<T> cases |
|
836 // |
|
837 |
|
838 template<class T> |
|
839 inline |
|
840 bool operator == ( none_t x, optional<T> const& y ) |
|
841 { return equal_pointees(optional<T>() ,y); } |
|
842 |
|
843 template<class T> |
|
844 inline |
|
845 bool operator < ( none_t x, optional<T> const& y ) |
|
846 { return less_pointees(optional<T>() ,y); } |
|
847 |
|
848 template<class T> |
|
849 inline |
|
850 bool operator != ( none_t x, optional<T> const& y ) |
|
851 { return !( x == y ) ; } |
|
852 |
|
853 template<class T> |
|
854 inline |
|
855 bool operator > ( none_t x, optional<T> const& y ) |
|
856 { return y < x ; } |
|
857 |
|
858 template<class T> |
|
859 inline |
|
860 bool operator <= ( none_t x, optional<T> const& y ) |
|
861 { return !( y < x ) ; } |
|
862 |
|
863 template<class T> |
|
864 inline |
|
865 bool operator >= ( none_t x, optional<T> const& y ) |
|
866 { return !( x < y ) ; } |
|
867 |
|
868 // |
|
869 // The following swap implementation follows the GCC workaround as found in |
|
870 // "boost/detail/compressed_pair.hpp" |
|
871 // |
|
872 namespace optional_detail { |
|
873 |
|
874 // GCC < 3.2 gets the using declaration at namespace scope (FLC, DWA) |
|
875 #if BOOST_WORKAROUND(__GNUC__, < 3) \ |
|
876 || BOOST_WORKAROUND(__GNUC__, == 3) && __GNUC_MINOR__ <= 2 |
|
877 using std::swap; |
|
878 #define BOOST_OPTIONAL_STD_SWAP_INTRODUCED_AT_NS_SCOPE |
|
879 #endif |
|
880 |
|
881 // optional's swap: |
|
882 // If both are initialized, calls swap(T&, T&). If this swap throws, both will remain initialized but their values are now unspecified. |
|
883 // If only one is initialized, calls U.reset(*I), THEN I.reset(). |
|
884 // If U.reset(*I) throws, both are left UNCHANGED (U is kept uinitialized and I is never reset) |
|
885 // If both are uninitialized, do nothing (no-throw) |
|
886 template<class T> |
|
887 inline |
|
888 void optional_swap ( optional<T>& x, optional<T>& y ) |
|
889 { |
|
890 if ( !x && !!y ) |
|
891 { |
|
892 x.reset(*y); |
|
893 y.reset(); |
|
894 } |
|
895 else if ( !!x && !y ) |
|
896 { |
|
897 y.reset(*x); |
|
898 x.reset(); |
|
899 } |
|
900 else if ( !!x && !!y ) |
|
901 { |
|
902 // GCC > 3.2 and all other compilers have the using declaration at function scope (FLC) |
|
903 #ifndef BOOST_OPTIONAL_STD_SWAP_INTRODUCED_AT_NS_SCOPE |
|
904 // allow for Koenig lookup |
|
905 using std::swap ; |
|
906 #endif |
|
907 swap(*x,*y); |
|
908 } |
|
909 } |
|
910 |
|
911 } // namespace optional_detail |
|
912 |
|
913 template<class T> inline void swap ( optional<T>& x, optional<T>& y ) |
|
914 { |
|
915 optional_detail::optional_swap(x,y); |
|
916 } |
|
917 |
|
918 |
|
919 } // namespace boost |
|
920 |
|
921 #endif |
|
922 |