diff --git a/include/boost/optional/optional.hpp b/include/boost/optional/optional.hpp index 88041d1..2b066e9 100644 --- a/include/boost/optional/optional.hpp +++ b/include/boost/optional/optional.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2003, Fernando Luis Cacciola Carballal. +// Copyright (C) 2003, 2008 Fernando Luis Cacciola Carballal. // // Use, modification, and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at @@ -9,16 +9,20 @@ // You are welcome to contact the author at: // fernando_cacciola@hotmail.com // +// Revisions: +// 27 Apr 2008 (improved swap) Fernando Cacciola, Niels Dekker, Thorsten Ottosen +// #ifndef BOOST_OPTIONAL_OPTIONAL_FLC_19NOV2002_HPP #define BOOST_OPTIONAL_OPTIONAL_FLC_19NOV2002_HPP -#include -#include +#include +#include #include "boost/config.hpp" #include "boost/assert.hpp" #include "boost/type.hpp" #include "boost/type_traits/alignment_of.hpp" +#include "boost/type_traits/has_nothrow_constructor.hpp" #include "boost/type_traits/type_with_alignment.hpp" #include "boost/type_traits/remove_reference.hpp" #include "boost/type_traits/is_reference.hpp" @@ -27,7 +31,9 @@ #include "boost/mpl/not.hpp" #include "boost/detail/reference_content.hpp" #include "boost/none.hpp" +#include "boost/utility/addressof.hpp" #include "boost/utility/compare_pointees.hpp" +#include "boost/utility/in_place_factory.hpp" #include "boost/optional/optional_fwd.hpp" @@ -76,6 +82,15 @@ #define BOOST_OPTIONAL_WEAK_OVERLOAD_RESOLUTION #endif +#if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) > 302 \ + && !defined(__INTEL_COMPILER) +// GCC since 3.3 has may_alias attribute that helps to alleviate optimizer issues with +// regard to violation of the strict aliasing rules. The optional< T > storage type is marked +// with this attribute in order to let the compiler know that it will alias objects of type T +// and silence compilation warnings. +#define BOOST_OPTIONAL_DETAIL_USE_ATTRIBUTE_MAY_ALIAS +#endif + // Daniel Wallin discovered that bind/apply.hpp badly interacts with the apply<> // member template of a factory as used in the optional<> implementation. // He proposed this simple fix which is to move the call to apply<> outside @@ -105,7 +120,12 @@ template class aligned_storage { // Borland ICEs if unnamed unions are used for this! - union dummy_u + union + // This works around GCC warnings about breaking strict aliasing rules when casting storage address to T* +#if defined(BOOST_OPTIONAL_DETAIL_USE_ATTRIBUTE_MAY_ALIAS) + __attribute__((may_alias)) +#endif + dummy_u { char data[ sizeof(T) ]; BOOST_DEDUCED_TYPENAME type_with_alignment< @@ -114,8 +134,13 @@ class aligned_storage public: - void const* address() const { return &dummy_.data[0]; } - void * address() { return &dummy_.data[0]; } +#if defined(BOOST_OPTIONAL_DETAIL_USE_ATTRIBUTE_MAY_ALIAS) + void const* address() const { return &dummy_; } + void * address() { return &dummy_; } +#else + void const* address() const { return dummy_.data; } + void * address() { return dummy_.data; } +#endif } ; template @@ -149,7 +174,7 @@ class optional_base : public optional_tag typedef #if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) BOOST_DEDUCED_TYPENAME -#endif +#endif ::boost::detail::make_reference_content::type internal_type ; typedef aligned_storage storage_type ; @@ -200,7 +225,7 @@ class optional_base : public optional_tag { construct(val); } - + // Creates an optional initialized with 'val' IFF cond is true, otherwise creates an uninitialzed optional. // Can throw if T::T(T const&) does optional_base ( bool cond, argument_type val ) @@ -421,8 +446,22 @@ class optional_base : public optional_tag private : // internal_type can be either T or reference_content +#if defined(BOOST_OPTIONAL_DETAIL_USE_ATTRIBUTE_MAY_ALIAS) + // This workaround is supposed to silence GCC warnings about broken strict aliasing rules + internal_type const* get_object() const + { + union { void const* ap_pvoid; internal_type const* as_ptype; } caster = { m_storage.address() }; + return caster.as_ptype; + } + internal_type * get_object() + { + union { void* ap_pvoid; internal_type* as_ptype; } caster = { m_storage.address() }; + return caster.as_ptype; + } +#else internal_type const* get_object() const { return static_cast(m_storage.address()); } internal_type * get_object() { return static_cast (m_storage.address()); } +#endif // reference_content lacks an implicit conversion to T&, so the following is needed to obtain a proper reference. reference_const_type dereference( internal_type const* p, is_not_reference_tag ) const { return *p ; } @@ -513,12 +552,12 @@ class optional : public optional_detail::optional_base // Depending on the above some T ctor is called. // Can throw is the resolved T ctor throws. template - explicit optional ( Expr const& expr ) : base(expr,&expr) {} + explicit optional ( Expr const& expr ) : base(expr,boost::addressof(expr)) {} #endif // Creates a deep copy of another optional // Can throw if T::T(T const&) does - optional ( optional const& rhs ) : base(rhs) {} + optional ( optional const& rhs ) : base( static_cast(rhs) ) {} // No-throw (assuming T::~T() doesn't) ~optional() {} @@ -527,9 +566,9 @@ class optional : public optional_detail::optional_base // Assigns from an expression. See corresponding constructor. // Basic Guarantee: If the resolved T ctor throws, this is left UNINITIALIZED template - optional& operator= ( Expr expr ) + optional& operator= ( Expr const& expr ) { - this->assign_expr(expr,&expr); + this->assign_expr(expr,boost::addressof(expr)); return *this ; } #endif @@ -552,7 +591,7 @@ class optional : public optional_detail::optional_base // (NOTE: On BCB, this operator is not actually called and left is left UNMODIFIED in case of a throw) optional& operator= ( optional const& rhs ) { - this->assign( rhs ) ; + this->assign( static_cast(rhs) ) ; return *this ; } @@ -573,6 +612,14 @@ class optional : public optional_detail::optional_base return *this ; } + void swap( optional & arg ) + { + // allow for Koenig lookup + using boost::swap ; + swap(*this, arg); + } + + // Returns a reference to the value if this is initialized, otherwise, // the behaviour is UNDEFINED // No-throw @@ -582,7 +629,7 @@ class optional : public optional_detail::optional_base // Returns a copy of the value if this is initialized, 'v' otherwise reference_const_type get_value_or ( reference_const_type v ) const { return this->is_initialized() ? get() : v ; } reference_type get_value_or ( reference_type v ) { return this->is_initialized() ? get() : v ; } - + // Returns a pointer to the value if this is initialized, otherwise, // the behaviour is UNDEFINED // No-throw @@ -599,22 +646,22 @@ class optional : public optional_detail::optional_base // No-throw operator unspecified_bool_type() const { return this->safe_bool() ; } - // This is provided for those compilers which don't like the conversion to bool - // on some contexts. - bool operator!() const { return !this->is_initialized() ; } + // This is provided for those compilers which don't like the conversion to bool + // on some contexts. + bool operator!() const { return !this->is_initialized() ; } } ; // Returns optional(v) -template -inline +template +inline optional make_optional ( T const& v ) { return optional(v); } // Returns optional(cond,v) -template -inline +template +inline optional make_optional ( bool cond, T const& v ) { return optional(cond,v); @@ -880,44 +927,77 @@ namespace optional_detail { #define BOOST_OPTIONAL_STD_SWAP_INTRODUCED_AT_NS_SCOPE #endif -// optional's swap: -// If both are initialized, calls swap(T&, T&). If this swap throws, both will remain initialized but their values are now unspecified. -// If only one is initialized, calls U.reset(*I), THEN I.reset(). -// If U.reset(*I) throws, both are left UNCHANGED (U is kept uinitialized and I is never reset) -// If both are uninitialized, do nothing (no-throw) -template -inline -void optional_swap ( optional& x, optional& y ) -{ - if ( !x && !!y ) + template struct swap_selector; + + template<> + struct swap_selector { - x.reset(*y); - y.reset(); - } - else if ( !!x && !y ) - { - y.reset(*x); - x.reset(); - } - else if ( !!x && !!y ) - { -// GCC > 3.2 and all other compilers have the using declaration at function scope (FLC) + template + static void optional_swap ( optional& x, optional& y ) + { + bool hasX = x; + bool hasY = y; + + if ( !hasX && !hasY ) + return; + + if( !hasX ) + x = boost::in_place(); + else if ( !hasY ) + y = boost::in_place(); + + // GCC > 3.2 and all other compilers have the using declaration at function scope (FLC) #ifndef BOOST_OPTIONAL_STD_SWAP_INTRODUCED_AT_NS_SCOPE - // allow for Koenig lookup - using std::swap ; + // allow for Koenig lookup + using std::swap ; #endif - swap(*x,*y); - } -} + swap(*x,*y); + + if( !hasX ) + y = boost::none ; + else if( !hasY ) + x = boost::none ; + } + }; + + template<> + struct swap_selector + { + template + static void optional_swap ( optional& x, optional& y ) + { + if ( !x && !!y ) + { + x = *y; + y = boost::none ; + } + else if ( !!x && !y ) + { + y = *x ; + x = boost::none ; + } + else if ( !!x && !!y ) + { + // GCC > 3.2 and all other compilers have the using declaration at function scope (FLC) + #ifndef BOOST_OPTIONAL_STD_SWAP_INTRODUCED_AT_NS_SCOPE + // allow for Koenig lookup + using std::swap ; + #endif + swap(*x,*y); + } + } + }; } // namespace optional_detail +template +struct optional_swap_should_use_default_constructor : has_nothrow_default_constructor {} ; + template inline void swap ( optional& x, optional& y ) { - optional_detail::optional_swap(x,y); + optional_detail::swap_selector::value>::optional_swap(x, y); } - } // namespace boost #endif diff --git a/include/boost/optional/optional_io.hpp b/include/boost/optional/optional_io.hpp index 85a1857..9e0c807 100644 --- a/include/boost/optional/optional_io.hpp +++ b/include/boost/optional/optional_io.hpp @@ -13,19 +13,20 @@ #define BOOST_OPTIONAL_OPTIONAL_IO_FLC_19NOV2002_HPP #if defined __GNUC__ -# if (__GNUC__ == 2 && __GNUC_MINOR__ <= 97) +# if (__GNUC__ == 2 && __GNUC_MINOR__ <= 97) # define BOOST_OPTIONAL_NO_TEMPLATED_STREAMS # endif #endif // __GNUC__ #if defined BOOST_OPTIONAL_NO_TEMPLATED_STREAMS # include -#else +#else # include # include -#endif - +#endif +#include +#include #include "boost/optional/optional.hpp" #include "boost/utility/value_init.hpp" @@ -62,17 +63,30 @@ std::basic_istream& operator>>(std::basic_istream& in, optional& v) #endif { - if ( in.good() ) + if (in.good()) { int d = in.get(); - if ( d == ' ' ) + if (d == ' ') { - T x ; + T x; in >> x; - v = x ; + v = x; } else - v = optional() ; + { + if (d == '-') + { + d = in.get(); + + if (d == '-') + { + v = none; + return in; + } + } + + in.setstate( std::ios::failbit ); + } } return in; diff --git a/test/optional_test.cpp b/test/optional_test.cpp index 02ed181..e2e0dd5 100644 --- a/test/optional_test.cpp +++ b/test/optional_test.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2003, Fernando Luis Cacciola Carballal. +// Copyright (C) 2003, 2008 Fernando Luis Cacciola Carballal. // // Use, modification, and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at @@ -9,6 +9,9 @@ // You are welcome to contact the author at: // fernando_cacciola@hotmail.com // +// Revisions: +// 12 May 2008 (added more swap tests) +// #include #include #include @@ -16,6 +19,8 @@ #define BOOST_ENABLE_ASSERT_HANDLER #include "boost/bind/apply.hpp" // Included just to test proper interaction with boost::apply<> as reported by Daniel Wallin +#include "boost/mpl/bool.hpp" +#include "boost/mpl/bool_fwd.hpp" // For mpl::true_ and mpl::false_ #include "boost/optional/optional.hpp" @@ -153,27 +158,27 @@ void test_basics( T const* ) ob.reset(); check_is_pending_dtor( ARG(T) ) ; check_uninitialized(ob); - + } template void test_conditional_ctor_and_get_valur_or ( T const* ) { TRACE( std::endl << BOOST_CURRENT_FUNCTION ); - + T a(321); - + T z(123); - + optional const cdef0(false,a); - + optional def0(false,a); optional def1 = boost::make_optional(false,a); // T is not within boost so ADL won't find make_optional unqualified check_uninitialized(def0); check_uninitialized(def1); optional const co0(true,a); - + optional o0(true,a); optional o1 = boost::make_optional(true,a); // T is not within boost so ADL won't find make_optional unqualified @@ -181,65 +186,65 @@ void test_conditional_ctor_and_get_valur_or ( T const* ) check_initialized(o1); check_value(o0,a,z); check_value(o1,a,z); - + T b = def0.get_value_or(z); BOOST_CHECK( b == z ) ; - + b = get_optional_value_or(def0,z); BOOST_CHECK( b == z ) ; - + b = o0.get_value_or(z); BOOST_CHECK( b == a ) ; b = get_optional_value_or(o0,z); BOOST_CHECK( b == a ) ; - - + + T const& crz = z ; T& rz = z ; - + T const& crzz = def0.get_value_or(crz); BOOST_CHECK( crzz == crz ) ; - + T& rzz = def0.get_value_or(rz); BOOST_CHECK( rzz == rz ) ; - + T const& crzzz = get_optional_value_or(cdef0,crz); BOOST_CHECK( crzzz == crz ) ; - + T& rzzz = get_optional_value_or(def0,rz); BOOST_CHECK( rzzz == rz ) ; - + T const& crb = o0.get_value_or(crz); BOOST_CHECK( crb == a ) ; - + T& rb = o0.get_value_or(rz); BOOST_CHECK( rb == b ) ; - + T const& crbb = get_optional_value_or(co0,crz); BOOST_CHECK( crbb == b ) ; - + T const& crbbb = get_optional_value_or(o0,crz); BOOST_CHECK( crbbb == b ) ; - + T& rbb = get_optional_value_or(o0,rz); BOOST_CHECK( rbb == b ) ; - + T& ra = a ; - + optional defref(false,ra); BOOST_CHECK(!defref); - + optional ref(true,ra); BOOST_CHECK(!!ref); - + a = T(432); - + BOOST_CHECK( *ref == a ) ; - + T& r1 = defref.get_value_or(z); BOOST_CHECK( r1 == z ) ; - + T& r2 = ref.get_value_or(z); BOOST_CHECK( r2 == a ) ; } @@ -713,7 +718,7 @@ void test_relops( T const* ) optional opt0(v0); optional opt1(v1); optional opt2(v2); - + // Check identity BOOST_CHECK ( def0 == def0 ) ; BOOST_CHECK ( opt0 == opt0 ) ; @@ -751,7 +756,7 @@ void test_relops( T const* ) BOOST_CHECK ( opt1 > opt0 ) ; BOOST_CHECK ( opt1 <= opt2 ) ; BOOST_CHECK ( opt1 >= opt0 ) ; - + // Compare against a value directly BOOST_CHECK ( opt0 == v0 ) ; BOOST_CHECK ( opt0 != v1 ) ; @@ -794,7 +799,7 @@ void test_none( T const* ) BOOST_CHECK ( def0 == none ) ; BOOST_CHECK ( non_def != none ) ; BOOST_CHECK ( !def1 ) ; - BOOST_CHECK ( !(non_def < none) ) ; + BOOST_CHECK ( !(non_def < none) ) ; BOOST_CHECK ( non_def > none ) ; BOOST_CHECK ( !(non_def <= none) ) ; BOOST_CHECK ( non_def >= none ) ; @@ -814,11 +819,11 @@ void test_arrow( T const* ) optional oa(a) ; optional const coa(a) ; - + BOOST_CHECK ( coa->V() == 1234 ) ; - + oa->V() = 4321 ; - + BOOST_CHECK ( a.V() = 1234 ) ; BOOST_CHECK ( (*oa).V() = 4321 ) ; } @@ -927,6 +932,364 @@ void test_conversions2() BOOST_CHECK(*get(&opt1) == static_cast(f)); } + +namespace optional_swap_test +{ + class default_ctor_exception : public std::exception {} ; + class copy_ctor_exception : public std::exception {} ; + class assignment_exception : public std::exception {} ; + + // + // Base class for swap test classes. Its assignment should not be called, when swapping + // optional objects. (The default std::swap would do so.) + // + class base_class_with_forbidden_assignment + { + public: + base_class_with_forbidden_assignment & operator=(const base_class_with_forbidden_assignment &) + { + BOOST_CHECK(!"The assignment should not be used while swapping!"); + throw assignment_exception(); + } + + virtual ~base_class_with_forbidden_assignment() {} + }; + + // + // Class without default constructor + // + class class_without_default_ctor : public base_class_with_forbidden_assignment + { + public: + char data; + explicit class_without_default_ctor(char arg) : data(arg) {} + }; + + // + // Class whose default constructor should not be used by optional::swap! + // + class class_whose_default_ctor_should_not_be_used : public base_class_with_forbidden_assignment + { + public: + char data; + explicit class_whose_default_ctor_should_not_be_used(char arg) : data(arg) {} + + class_whose_default_ctor_should_not_be_used() + { + BOOST_CHECK(!"This default constructor should not be used while swapping!"); + throw default_ctor_exception(); + } + }; + + // + // Class whose default constructor should be used by optional::swap. + // Its copy constructor should be avoided! + // + class class_whose_default_ctor_should_be_used : public base_class_with_forbidden_assignment + { + public: + char data; + explicit class_whose_default_ctor_should_be_used(char arg) : data(arg) { } + + class_whose_default_ctor_should_be_used() : data('\0') { } + + class_whose_default_ctor_should_be_used(const class_whose_default_ctor_should_be_used &) + { + BOOST_CHECK(!"This copy constructor should not be used while swapping!"); + throw copy_ctor_exception(); + } + }; + + // + // Class template whose default constructor should be used by optional::swap. + // Its copy constructor should be avoided! + // + template + class template_whose_default_ctor_should_be_used : public base_class_with_forbidden_assignment + { + public: + T data; + explicit template_whose_default_ctor_should_be_used(T arg) : data(arg) { } + + template_whose_default_ctor_should_be_used() : data('\0') { } + + template_whose_default_ctor_should_be_used(const template_whose_default_ctor_should_be_used &) + { + BOOST_CHECK(!"This copy constructor should not be used while swapping!"); + throw copy_ctor_exception(); + } + }; + + // + // Class whose explicit constructor should be used by optional::swap. + // Its other constructors should be avoided! + // + class class_whose_explicit_ctor_should_be_used : public base_class_with_forbidden_assignment + { + public: + char data; + explicit class_whose_explicit_ctor_should_be_used(char arg) : data(arg) { } + + class_whose_explicit_ctor_should_be_used() + { + BOOST_CHECK(!"This default constructor should not be used while swapping!"); + throw default_ctor_exception(); + } + + class_whose_explicit_ctor_should_be_used(const class_whose_explicit_ctor_should_be_used &) + { + BOOST_CHECK(!"This copy constructor should not be used while swapping!"); + throw copy_ctor_exception(); + } + }; + + void swap(class_whose_default_ctor_should_not_be_used & lhs, class_whose_default_ctor_should_not_be_used & rhs) + { + std::swap(lhs.data, rhs.data); + } + + void swap(class_whose_default_ctor_should_be_used & lhs, class_whose_default_ctor_should_be_used & rhs) + { + std::swap(lhs.data, rhs.data); + } + + void swap(class_without_default_ctor & lhs, class_without_default_ctor & rhs) + { + std::swap(lhs.data, rhs.data); + } + + void swap(class_whose_explicit_ctor_should_be_used & lhs, class_whose_explicit_ctor_should_be_used & rhs) + { + std::swap(lhs.data, rhs.data); + } + + template + void swap(template_whose_default_ctor_should_be_used & lhs, template_whose_default_ctor_should_be_used & rhs) + { + std::swap(lhs.data, rhs.data); + } + + // + // optional::swap should be customized when neither the copy constructor + // nor the default constructor of T are supposed to be used when swapping, e.g., + // for the following type T = class_whose_explicit_ctor_should_be_used. + // + void swap(boost::optional & x, boost::optional & y) + { + bool hasX = x; + bool hasY = y; + + if ( !hasX && !hasY ) + return; + + if( !hasX ) + x = boost::in_place('\0'); + else if ( !hasY ) + y = boost::in_place('\0'); + + optional_swap_test::swap(*x,*y); + + if( !hasX ) + y = boost::none ; + else if( !hasY ) + x = boost::none ; + } + + +} // End of namespace optional_swap_test. + + +namespace boost { + +// +// Compile time tweaking on whether or not swap should use the default constructor: +// + +template <> struct optional_swap_should_use_default_constructor< + optional_swap_test::class_whose_default_ctor_should_be_used> : mpl::true_ {} ; + +template <> struct optional_swap_should_use_default_constructor< + optional_swap_test::class_whose_default_ctor_should_not_be_used> : mpl::false_ {} ; + +template struct optional_swap_should_use_default_constructor< + optional_swap_test::template_whose_default_ctor_should_be_used > : mpl::true_ {} ; + + +// +// Specialization of boost::swap: +// +template <> +void swap(optional & x, optional & y) +{ + optional_swap_test::swap(x, y); +} + +} // namespace boost + + +namespace std { + +// +// Specializations of std::swap: +// + +template <> +void swap(optional_swap_test::class_whose_default_ctor_should_be_used & x, optional_swap_test::class_whose_default_ctor_should_be_used & y) +{ + optional_swap_test::swap(x, y); +} + +template <> +void swap(optional_swap_test::class_whose_default_ctor_should_not_be_used & x, optional_swap_test::class_whose_default_ctor_should_not_be_used & y) +{ + optional_swap_test::swap(x, y); +} + +template <> +void swap(optional_swap_test::class_without_default_ctor & x, optional_swap_test::class_without_default_ctor & y) +{ + optional_swap_test::swap(x, y); +} + +template <> +void swap(optional_swap_test::class_whose_explicit_ctor_should_be_used & x, optional_swap_test::class_whose_explicit_ctor_should_be_used & y) +{ + optional_swap_test::swap(x, y); +} + +} // namespace std + + +// +// Tests whether the swap function works properly for optional. +// Assumes that T has one data member, of type char. +// Returns true iff the test is passed. +// +template +bool test_swap_function( T const* ) +{ + const boost::unit_test::counter_t counter_before_test = boost::minimal_test::errors_counter(); + try + { + optional obj1; + optional obj2('a'); + + // Self-swap should not have any effect. + swap(obj1, obj1); + swap(obj2, obj2); + BOOST_CHECK(!obj1); + BOOST_CHECK(!!obj2 && obj2->data == 'a'); + + // Call non-member swap. + swap(obj1, obj2); + + // Test if obj1 and obj2 are really swapped. + BOOST_CHECK(!!obj1 && obj1->data == 'a'); + BOOST_CHECK(!obj2); + + // Call non-member swap one more time. + swap(obj1, obj2); + + // Test if obj1 and obj2 are swapped back. + BOOST_CHECK(!obj1); + BOOST_CHECK(!!obj2 && obj2->data == 'a'); + } + catch(const std::exception &) + { + // The swap function should not throw, for our test cases. + return false ; + } + return boost::minimal_test::errors_counter() == counter_before_test ; +} + +// +// Tests whether the optional::swap member function works properly. +// Assumes that T has one data member, of type char. +// Returns true iff the test is passed. +// +template +bool test_swap_member_function( T const* ) +{ + const boost::unit_test::counter_t counter_before_test = boost::minimal_test::errors_counter(); + try + { + optional obj1; + optional obj2('a'); + + // Self-swap should not have any effect. + obj1.swap(obj1); + obj2.swap(obj2); + BOOST_CHECK(!obj1); + BOOST_CHECK(!!obj2 && obj2->data == 'a'); + + // Call member swap. + obj1.swap(obj2); + + // Test if obj1 and obj2 are really swapped. + BOOST_CHECK(!!obj1 && obj1->data == 'a'); + BOOST_CHECK(!obj2); + + // Call member swap one more time. + obj1.swap(obj2); + + // Test if obj1 and obj2 are swapped back. + BOOST_CHECK(!obj1); + BOOST_CHECK(!!obj2 && obj2->data == 'a'); + } + catch(const std::exception &) + { + // The optional::swap member function should not throw, for our test cases. + return false ; + } + return boost::minimal_test::errors_counter() == counter_before_test ; +} + + +// +// Tests compile time tweaking of swap, by means of +// optional_swap_should_use_default_constructor. +// +void test_swap_tweaking() +{ + BOOST_CHECK( test_swap_function( ARG(optional_swap_test::class_without_default_ctor) ) ); + BOOST_CHECK( test_swap_function( ARG(optional_swap_test::class_whose_default_ctor_should_be_used) ) ); + BOOST_CHECK( test_swap_function( ARG(optional_swap_test::class_whose_default_ctor_should_not_be_used) ) ); + BOOST_CHECK( test_swap_function( ARG(optional_swap_test::class_whose_explicit_ctor_should_be_used) ) ); + BOOST_CHECK( test_swap_function( ARG(optional_swap_test::template_whose_default_ctor_should_be_used) ) ); + BOOST_CHECK( test_swap_member_function( ARG(optional_swap_test::class_without_default_ctor) ) ); + BOOST_CHECK( test_swap_member_function( ARG(optional_swap_test::class_whose_default_ctor_should_be_used) ) ); + BOOST_CHECK( test_swap_member_function( ARG(optional_swap_test::class_whose_default_ctor_should_not_be_used) ) ); + BOOST_CHECK( test_swap_member_function( ARG(optional_swap_test::class_whose_explicit_ctor_should_be_used) ) ); + BOOST_CHECK( test_swap_member_function( ARG(optional_swap_test::template_whose_default_ctor_should_be_used) ) ); +} + +// Test for support for classes with overridden operator& +class CustomAddressOfClass +{ + int n; + +public: + CustomAddressOfClass() : n(0) {} + CustomAddressOfClass(CustomAddressOfClass const& that) : n(that.n) {} + explicit CustomAddressOfClass(int m) : n(m) {} + int* operator& () { return &n; } + bool operator== (CustomAddressOfClass const& that) const { return n == that.n; } +}; + +void test_custom_addressof_operator() +{ + boost::optional< CustomAddressOfClass > o1(CustomAddressOfClass(10)); + BOOST_CHECK(!!o1); + BOOST_CHECK(o1.get() == CustomAddressOfClass(10)); + + o1 = CustomAddressOfClass(20); + BOOST_CHECK(!!o1); + BOOST_CHECK(o1.get() == CustomAddressOfClass(20)); + + o1 = boost::none; + BOOST_CHECK(!o1); +} + int test_main( int, char* [] ) { try @@ -936,6 +1299,8 @@ int test_main( int, char* [] ) test_no_implicit_conversions(); test_conversions1(); test_conversions2(); + test_swap_tweaking(); + test_custom_addressof_operator(); } catch ( ... ) { diff --git a/test/optional_test_io.cpp b/test/optional_test_io.cpp index 13e8a5d..d4ee207 100644 --- a/test/optional_test_io.cpp +++ b/test/optional_test_io.cpp @@ -55,10 +55,14 @@ void test2( Opt o, Opt buff ) { stringstream s ; - s << o ; - s >> buff ; + const int markv = 123 ; + int mark = 0 ; + + s << o << " " << markv ; + s >> buff >> mark ; BOOST_ASSERT( buff == o ) ; + BOOST_ASSERT( mark == markv ) ; } @@ -77,7 +81,6 @@ int test_main( int, char* [] ) { test(1,2); test(string("hello"),string("buffer")); - test(string(""),string("buffer")); } catch ( ... ) {