diff --git a/doc/1A_on_performance.qbk b/doc/1A_on_performance.qbk
index 5fd749a..6459ffe 100644
--- a/doc/1A_on_performance.qbk
+++ b/doc/1A_on_performance.qbk
@@ -1,7 +1,7 @@
[section Performance considerations]
-Technical details aside, the memory layout of `optional` is more-less this:
+Technical details aside, the memory layout of `optional` for a generic `T` is more-less this:
template
class optional
@@ -9,8 +9,33 @@ Technical details aside, the memory layout of `optional` is more-less this:
bool _initialized;
std::aligned_storage_t _storage;
};
+
+Lifetime of the `T` inside `_storage` is manually controlled with placement-`new`s and pseudo-destructor calls. However, for trivial `T`s we use a different way of storage, by simply holding a `T`:
-But for the purpose of this analysis, considering memory layouts, we can think of it as:
+ template
+ class optional
+ {
+ bool _initialized;
+ T _storage;
+ };
+
+We call it a ['direct] storage. This makes `optional` a trivially-copyable type for trivial `T`s. This only works for compilers that support defaulted functions and type traits. On compilers without defaulted functions we still use the direct storage, but `optional` is no longer recognized as trivially-copyable. On compilers that do not fully support type traits, we still use the direct storage for scalar types, but we leave the programmer a way of customizing her type, so that it is reconized by `optional` as trivial, by specializing type trait `boost::opitonal_config::is_type_trivial`:
+
+ struct X // not trivial
+ {
+ X() {}
+ };
+
+ namespace boost { namespace optional_config {
+
+ template <> struct is_type_trivial : boost::true_type {};
+
+ }}
+
+
+[heading Controlling the size]
+
+For the purpose of the followin analysis, considering memory layouts, we can think of it as:
template
class optional
diff --git a/doc/91_relnotes.qbk b/doc/91_relnotes.qbk
index d9ca103..0c18f93 100644
--- a/doc/91_relnotes.qbk
+++ b/doc/91_relnotes.qbk
@@ -11,6 +11,11 @@
[section:relnotes Release Notes]
+[heading Boost Release 1.66]
+
+* On newer compilers `optional` is now trivially-copyable for trivial `T`s. This uses a different storage (just `T` rather than `aligned_storage`). We require the compiler to support defaulted functions and type traits. Otherwise, we still use the the plain storage for scalar types.
+
+
[heading Boost Release 1.63]
* Added two new in-place constructors. They work similarly to `emplace()` functions: they initialize the contained value by perfect-forwarding the obtained arguments. One constructor always initializes the contained value, the other based on a boolean condition.
* Syntax `o = {}` now correctly un-initializes optional, just like in `std::optional`.
diff --git a/doc/html/boost_optional/relnotes.html b/doc/html/boost_optional/relnotes.html
index 1b161ed..5ccc2d7 100644
--- a/doc/html/boost_optional/relnotes.html
+++ b/doc/html/boost_optional/relnotes.html
@@ -28,6 +28,19 @@
+-
+ On newer compilers
optional
+ is now trivially-copyable for trivial T
s.
+ This uses a different storage (just T
+ rather than aligned_storage
).
+ We require the compiler to support defaulted functions and type traits.
+ Otherwise, we still use the the plain storage for scalar types.
+
+
@@ -51,7 +64,7 @@
@@ -59,7 +72,7 @@
Fixed Trac #12179.
@@ -102,7 +115,7 @@
@@ -113,7 +126,7 @@
#11203.
@@ -127,7 +140,7 @@
@@ -163,7 +176,7 @@
@@ -173,7 +186,7 @@
to fix C++03 compile error on logic_error("...")
".
diff --git a/doc/html/boost_optional/tutorial/performance_considerations.html b/doc/html/boost_optional/tutorial/performance_considerations.html
index 5ce93f9..2c796da 100644
--- a/doc/html/boost_optional/tutorial/performance_considerations.html
+++ b/doc/html/boost_optional/tutorial/performance_considerations.html
@@ -29,7 +29,8 @@
Technical details aside, the memory layout of optional<T>
- is more-less this:
+ for a generic T
is more-less
+ this:
template <typename T>
class optional
@@ -39,8 +40,50 @@
};
- But for the purpose of this analysis, considering memory layouts, we can
- think of it as:
+ Lifetime of the T
inside
+ _storage
is manually controlled
+ with placement-new
s and pseudo-destructor
+ calls. However, for trivial T
s
+ we use a different way of storage, by simply holding a T
:
+
+template <typename T>
+class optional
+{
+ bool _initialized;
+ T _storage;
+};
+
+
+ We call it a direct storage. This makes optional<T>
a
+ trivially-copyable type for trivial T
s.
+ This only works for compilers that support defaulted functions and type traits.
+ On compilers without defaulted functions we still use the direct storage,
+ but optional<T>
is
+ no longer recognized as trivially-copyable. On compilers that do not fully
+ support type traits, we still use the direct storage for scalar types, but
+ we leave the programmer a way of customizing her type, so that it is reconized
+ by optional
as trivial, by
+ specializing type trait boost::opitonal_config::is_type_trivial
:
+
+struct X
+{
+ X() {}
+};
+
+namespace boost { namespace optional_config {
+
+ template <> struct is_type_trivial<X> : boost::true_type {};
+
+}}
+
+
+
+ For the purpose of the followin analysis, considering memory layouts, we
+ can think of it as:
template <typename T>
class optional
@@ -143,7 +186,7 @@
diff --git a/doc/html/index.html b/doc/html/index.html
index 1429a21..de3b006 100644
--- a/doc/html/index.html
+++ b/doc/html/index.html
@@ -146,7 +146,7 @@
-Last revised: May 17, 2017 at 23:01:39 GMT |
+Last revised: October 28, 2017 at 14:38:14 GMT |
|
diff --git a/include/boost/optional/detail/optional_trivially_copyable_base.hpp b/include/boost/optional/detail/optional_trivially_copyable_base.hpp
new file mode 100644
index 0000000..1deaeab
--- /dev/null
+++ b/include/boost/optional/detail/optional_trivially_copyable_base.hpp
@@ -0,0 +1,499 @@
+// trivilally-copyable version of the storage
+
+template
+class tc_optional_base : public optional_tag
+{
+ private :
+
+ typedef tc_optional_base this_type ;
+
+ protected :
+
+ typedef T value_type ;
+
+ protected:
+ typedef T & reference_type ;
+ typedef T const& reference_const_type ;
+#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
+ typedef T && rval_reference_type ;
+ typedef T && reference_type_of_temporary_wrapper ;
+#endif
+ typedef T * pointer_type ;
+ typedef T const* pointer_const_type ;
+ typedef T const& argument_type ;
+
+ tc_optional_base()
+ :
+ m_initialized(false) {}
+
+ tc_optional_base ( none_t )
+ :
+ m_initialized(false) {}
+
+ tc_optional_base ( argument_type val )
+ :
+ m_initialized(true), m_storage(val) {}
+
+ tc_optional_base ( bool cond, argument_type val )
+ :
+ m_initialized(cond), m_storage(val) {}
+
+ // tc_optional_base ( tc_optional_base const& ) = default;
+
+
+#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
+
+ template
+ explicit tc_optional_base ( Expr&& expr, PtrExpr const* tag )
+ :
+ m_initialized(false)
+ {
+ construct(boost::forward(expr),tag);
+ }
+
+#else
+ // This is used for both converting and in-place constructions.
+ // Derived classes use the 'tag' to select the appropriate
+ // implementation (the correct 'construct()' overload)
+ template
+ explicit tc_optional_base ( Expr const& expr, Expr const* tag )
+ :
+ m_initialized(false)
+ {
+ construct(expr,tag);
+ }
+
+#endif
+
+ // tc_optional_base& operator= ( tc_optional_base const& ) = default;
+ // ~tc_optional_base() = default;
+
+ // Assigns from another optional (deep-copies the rhs value)
+ void assign ( tc_optional_base const& rhs )
+ {
+ this->operator=(rhs);
+ }
+
+ // Assigns from another _convertible_ optional (deep-copies the rhs value)
+ template
+ void assign ( optional const& rhs )
+ {
+ if ( rhs.is_initialized() )
+#ifndef BOOST_OPTIONAL_CONFIG_RESTORE_ASSIGNMENT_OF_NONCONVERTIBLE_TYPES
+ m_storage = rhs.get();
+#else
+ m_storage = static_cast(rhs.get());
+#endif
+
+ m_initialized = rhs.is_initialized();
+ }
+
+#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
+ // move-assigns from another _convertible_ optional (deep-moves from the rhs value)
+ template
+ void assign ( optional&& rhs )
+ {
+ typedef BOOST_DEDUCED_TYPENAME optional::rval_reference_type ref_type;
+ if ( rhs.is_initialized() )
+ m_storage = static_cast(rhs.get());
+ m_initialized = rhs.is_initialized();
+ }
+#endif
+
+ void assign ( argument_type val )
+ {
+ construct(val);
+ }
+
+ void assign ( none_t ) { destroy(); }
+
+#ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT
+
+#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
+ template
+ void assign_expr ( Expr&& expr, ExprPtr const* tag )
+ {
+ construct(boost::forward(expr),tag);
+ }
+#else
+ template
+ void assign_expr ( Expr const& expr, Expr const* tag )
+ {
+ construct(expr,tag);
+ }
+#endif
+
+#endif
+
+ public :
+
+ // **DEPPRECATED** Destroys the current value, if any, leaving this UNINITIALIZED
+ // No-throw (assuming T::~T() doesn't)
+ void reset() BOOST_NOEXCEPT { destroy(); }
+
+ // **DEPPRECATED** Replaces the current value -if any- with 'val'
+ void reset ( argument_type val ) BOOST_NOEXCEPT { assign(val); }
+
+ // Returns a pointer to the value if this is initialized, otherwise,
+ // returns NULL.
+ // No-throw
+ pointer_const_type get_ptr() const { return m_initialized ? get_ptr_impl() : 0 ; }
+ pointer_type get_ptr() { return m_initialized ? get_ptr_impl() : 0 ; }
+
+ bool is_initialized() const { return m_initialized ; }
+
+ protected :
+
+ void construct ( argument_type val )
+ {
+ m_storage = val ;
+ m_initialized = true ;
+ }
+
+
+#if (!defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES) && (!defined BOOST_NO_CXX11_VARIADIC_TEMPLATES)
+ // Constructs in-place
+ // upon exception *this is always uninitialized
+ template
+ void construct ( in_place_init_t, Args&&... args )
+ {
+ m_storage = value_type( boost::forward(args)... ) ;
+ m_initialized = true ;
+ }
+
+ template
+ void emplace_assign ( Args&&... args )
+ {
+ construct(in_place_init, boost::forward(args)...);
+ }
+
+ template
+ explicit tc_optional_base ( in_place_init_t, Args&&... args )
+ :
+ m_initialized(false)
+ {
+ construct(in_place_init, boost::forward(args)...);
+ }
+
+ template
+ explicit tc_optional_base ( in_place_init_if_t, bool cond, Args&&... args )
+ :
+ m_initialized(false)
+ {
+ if ( cond )
+ construct(in_place_init, boost::forward(args)...);
+ }
+#elif (!defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES)
+ template
+ void construct ( in_place_init_t, Arg&& arg )
+ {
+ m_storage = value_type( boost::forward(arg) );
+ m_initialized = true ;
+ }
+
+ void construct ( in_place_init_t )
+ {
+ m_storage = value_type();
+ m_initialized = true ;
+ }
+
+ template
+ void emplace_assign ( Arg&& arg )
+ {
+ construct(in_place_init, boost::forward(arg)) ;
+ }
+
+ void emplace_assign ()
+ {
+ construct(in_place_init) ;
+ }
+
+ template
+ explicit tc_optional_base ( in_place_init_t, Arg&& arg )
+ :
+ m_initialized(false)
+ {
+ construct(in_place_init, boost::forward(arg));
+ }
+
+ explicit tc_optional_base ( in_place_init_t )
+ :
+ m_initialized(false), m_storage() {}
+
+ template
+ explicit tc_optional_base ( in_place_init_if_t, bool cond, Arg&& arg )
+ :
+ m_initialized(false)
+ {
+ if ( cond )
+ construct(in_place_init, boost::forward(arg));
+ }
+
+ explicit tc_optional_base ( in_place_init_if_t, bool cond )
+ :
+ m_initialized(false)
+ {
+ if ( cond )
+ construct(in_place_init);
+ }
+
+#else
+
+ template
+ void construct ( in_place_init_t, const Arg& arg )
+ {
+ m_storage = value_type( arg );
+ m_initialized = true ;
+ }
+
+ template
+ void construct ( in_place_init_t, Arg& arg )
+ {
+ m_storage = value_type( arg );
+ m_initialized = true ;
+ }
+
+ void construct ( in_place_init_t )
+ {
+ m_storage = value_type();
+ m_initialized = true ;
+ }
+
+ template
+ void emplace_assign ( const Arg& arg )
+ {
+ construct(in_place_init, arg);
+ }
+
+ template
+ void emplace_assign ( Arg& arg )
+ {
+ construct(in_place_init, arg);
+ }
+
+ void emplace_assign ()
+ {
+ construct(in_place_init);
+ }
+
+ template
+ explicit tc_optional_base ( in_place_init_t, const Arg& arg )
+ : m_initialized(false)
+ {
+ construct(in_place_init, arg);
+ }
+
+ template
+ explicit tc_optional_base ( in_place_init_t, Arg& arg )
+ : m_initialized(false)
+ {
+ construct(in_place_init, arg);
+ }
+
+ explicit tc_optional_base ( in_place_init_t )
+ : m_initialized(false)
+ {
+ construct(in_place_init);
+ }
+
+ template
+ explicit tc_optional_base ( in_place_init_if_t, bool cond, const Arg& arg )
+ : m_initialized(false)
+ {
+ if ( cond )
+ construct(in_place_init, arg);
+ }
+
+ template
+ explicit tc_optional_base ( in_place_init_if_t, bool cond, Arg& arg )
+ : m_initialized(false)
+ {
+ if ( cond )
+ construct(in_place_init, arg);
+ }
+
+ explicit tc_optional_base ( in_place_init_if_t, bool cond )
+ : m_initialized(false)
+ {
+ if ( cond )
+ construct(in_place_init);
+ }
+#endif
+
+#ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT
+
+#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
+ // Constructs in-place using the given factory
+ template
+ void construct ( Expr&& factory, in_place_factory_base const* )
+ {
+ boost_optional_detail::construct(factory, boost::addressof(m_storage));
+ m_initialized = true ;
+ }
+
+ // Constructs in-place using the given typed factory
+ template
+ void construct ( Expr&& factory, typed_in_place_factory_base const* )
+ {
+ factory.apply(boost::addressof(m_storage)) ;
+ m_initialized = true ;
+ }
+
+ template
+ void assign_expr_to_initialized ( Expr&& factory, in_place_factory_base const* tag )
+ {
+ destroy();
+ construct(factory,tag);
+ }
+
+ // Constructs in-place using the given typed factory
+ template
+ void assign_expr_to_initialized ( Expr&& factory, typed_in_place_factory_base const* tag )
+ {
+ destroy();
+ construct(factory,tag);
+ }
+
+#else
+ // Constructs in-place using the given factory
+ template
+ void construct ( Expr const& factory, in_place_factory_base const* )
+ {
+ boost_optional_detail::construct(factory, m_storage.address());
+ m_initialized = true ;
+ }
+
+ // Constructs in-place using the given typed factory
+ template
+ void construct ( Expr const& factory, typed_in_place_factory_base const* )
+ {
+ factory.apply(boost::addressof(m_storage)) ;
+ m_initialized = true ;
+ }
+
+ template
+ void assign_expr_to_initialized ( Expr const& factory, in_place_factory_base const* tag )
+ {
+ destroy();
+ construct(factory,tag);
+ }
+
+ // Constructs in-place using the given typed factory
+ template
+ void assign_expr_to_initialized ( Expr const& factory, typed_in_place_factory_base const* tag )
+ {
+ destroy();
+ construct(factory,tag);
+ }
+#endif
+
+#endif
+
+#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
+ // Constructs using any expression implicitly convertible to the single argument
+ // of a one-argument T constructor.
+ // Converting constructions of optional from optional uses this function with
+ // 'Expr' being of type 'U' and relying on a converting constructor of T from U.
+ template
+ void construct ( Expr&& expr, void const* )
+ {
+ m_storage = value_type(boost::forward(expr)) ;
+ m_initialized = true ;
+ }
+
+ // Assigns using a form any expression implicitly convertible to the single argument
+ // of a T's assignment operator.
+ // Converting assignments of optional from optional uses this function with
+ // 'Expr' being of type 'U' and relying on a converting assignment of T from U.
+ template
+ void assign_expr_to_initialized ( Expr&& expr, void const* )
+ {
+ assign_value( boost::forward(expr) );
+ }
+#else
+ // Constructs using any expression implicitly convertible to the single argument
+ // of a one-argument T constructor.
+ // Converting constructions of optional from optional uses this function with
+ // 'Expr' being of type 'U' and relying on a converting constructor of T from U.
+ template
+ void construct ( Expr const& expr, void const* )
+ {
+ m_storage = value_type(expr) ;
+ m_initialized = true ;
+ }
+
+ // Assigns using a form any expression implicitly convertible to the single argument
+ // of a T's assignment operator.
+ // Converting assignments of optional from optional uses this function with
+ // 'Expr' being of type 'U' and relying on a converting assignment of T from U.
+ template
+ void assign_expr_to_initialized ( Expr const& expr, void const* )
+ {
+ assign_value(expr);
+ }
+
+#endif
+
+#ifdef BOOST_OPTIONAL_WEAK_OVERLOAD_RESOLUTION
+ // BCB5.64 (and probably lower versions) workaround.
+ // The in-place factories are supported by means of catch-all constructors
+ // and assignment operators (the functions are parameterized in terms of
+ // an arbitrary 'Expr' type)
+ // This compiler incorrectly resolves the overload set and sinks optional and optional
+ // to the 'Expr'-taking functions even though explicit overloads are present for them.
+ // Thus, the following overload is needed to properly handle the case when the 'lhs'
+ // is another optional.
+ //
+ // For VC<=70 compilers this workaround dosen't work becasue the comnpiler issues and error
+ // instead of choosing the wrong overload
+ //
+#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
+ // Notice that 'Expr' will be optional or optional (but not tc_optional_base<..>)
+ template
+ void construct ( Expr&& expr, optional_tag const* )
+ {
+ if ( expr.is_initialized() )
+ {
+ // An exception can be thrown here.
+ // It it happens, THIS will be left uninitialized.
+ m_storage = value_type(boost::move(expr.get())) ;
+ m_initialized = true ;
+ }
+ }
+#else
+ // Notice that 'Expr' will be optional or optional (but not tc_optional_base<..>)
+ template
+ void construct ( Expr const& expr, optional_tag const* )
+ {
+ if ( expr.is_initialized() )
+ {
+ // An exception can be thrown here.
+ // It it happens, THIS will be left uninitialized.
+ m_storage = value_type(expr.get()) ;
+ m_initialized = true ;
+ }
+ }
+#endif
+#endif // defined BOOST_OPTIONAL_WEAK_OVERLOAD_RESOLUTION
+
+ void assign_value ( argument_type val ) { m_storage = val; }
+#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
+ void assign_value ( rval_reference_type val ) { m_storage = static_cast(val); }
+#endif
+
+ void destroy()
+ {
+ m_initialized = false;
+ }
+
+ reference_const_type get_impl() const { return m_storage ; }
+ reference_type get_impl() { return m_storage ; }
+
+ pointer_const_type get_ptr_impl() const { return boost::addressof(m_storage); }
+ pointer_type get_ptr_impl() { return boost::addressof(m_storage); }
+
+ private :
+
+ bool m_initialized ;
+ T m_storage ;
+} ;
\ No newline at end of file
diff --git a/include/boost/optional/optional.hpp b/include/boost/optional/optional.hpp
index a75bf90..54fca4e 100644
--- a/include/boost/optional/optional.hpp
+++ b/include/boost/optional/optional.hpp
@@ -1,5 +1,5 @@
// Copyright (C) 2003, 2008 Fernando Luis Cacciola Carballal.
-// Copyright (C) 2014 - 2016 Andrzej Krzemienski.
+// Copyright (C) 2014 - 2017 Andrzej Krzemienski.
//
// Use, modification, and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
@@ -36,13 +36,22 @@
#include
#include
#include
+#include
+#include
+#include
+#include
+#include
+#include
#include
+#include
#include
#include
#include
#include
#include
#include
+#include
+#include
#include
#include
#include
@@ -178,6 +187,7 @@ class optional_base : public optional_tag
// Creates a deep move of another optional
// Can throw if T::T(T&&) does
optional_base ( optional_base&& rhs )
+ BOOST_NOEXCEPT_IF(::boost::is_nothrow_move_constructible::value)
:
m_initialized(false)
{
@@ -210,6 +220,20 @@ class optional_base : public optional_tag
#endif
+ optional_base& operator= ( optional_base const& rhs )
+ {
+ this->assign(rhs);
+ return *this;
+ }
+
+#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
+ optional_base& operator= ( optional_base && rhs )
+ BOOST_NOEXCEPT_IF(::boost::is_nothrow_move_constructible::value && ::boost::is_nothrow_move_assignable::value)
+ {
+ this->assign(static_cast(rhs));
+ return *this;
+ }
+#endif
// No-throw (assuming T::~T() doesn't)
~optional_base() { destroy() ; }
@@ -735,6 +759,10 @@ class optional_base : public optional_tag
storage_type m_storage ;
} ;
+
+
+#include
+
// definition of metafunciton is_optional_val_init_candidate
template
struct is_optional_related
@@ -776,13 +804,46 @@ struct is_optional_val_init_candidate
: boost::conditional< !is_optional_related::value && is_convertible_to_T_or_factory::value
, boost::true_type, boost::false_type>::type
{};
-
+
+
+template
+struct is_type_trivially_copyable
+ : boost::conditional<(boost::has_trivial_copy_constructor::value &&
+ boost::has_trivial_move_constructor::value &&
+ boost::has_trivial_destructor::value &&
+ boost::has_trivial_move_assign::value &&
+ boost::has_trivial_assign::value),
+ boost::true_type, boost::false_type>::type
+{};
+
} // namespace optional_detail
+namespace optional_config {
+
+template
+struct is_type_trivial
+ : boost::conditional< (optional_detail::is_type_trivially_copyable::value && boost::has_trivial_default_constructor::value) ||
+ (boost::is_scalar::value && !boost::is_const::value && !boost::is_volatile::value)
+ , boost::true_type, boost::false_type>::type
+{};
+
+} // namespace optional_config
+
+
+#ifndef BOOST_OPTIONAL_CONFIG_NO_SPEC_FOR_TRIVIAL_TYPES
+# define BOOST_OPTIONAL_BASE_TYPE(T) boost::conditional< optional_config::is_type_trivial::value, \
+ optional_detail::tc_optional_base, \
+ optional_detail::optional_base \
+ >::type
+#else
+# define BOOST_OPTIONAL_BASE_TYPE(T) optional_detail::optional_base
+#endif
+
template
-class optional : public optional_detail::optional_base
+class optional
+ : public BOOST_OPTIONAL_BASE_TYPE(T)
{
- typedef optional_detail::optional_base base ;
+ typedef typename BOOST_OPTIONAL_BASE_TYPE(T) base ;
public :
@@ -842,7 +903,7 @@ class optional : public optional_detail::optional_base
)
:
base()
- {
+ {
if ( rhs.is_initialized() )
this->construct(rhs.get());
}
@@ -893,15 +954,24 @@ class optional : public optional_detail::optional_base
// Creates a deep copy of another optional
// Can throw if T::T(T const&) does
+#ifndef BOOST_NO_CXX11_DEFAULTED_FUNCTIONS
+ optional ( optional const& ) = default;
+#else
optional ( optional const& rhs ) : base( static_cast(rhs) ) {}
+#endif
#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
// Creates a deep move of another optional
// Can throw if T::T(T&&) does
+
+#ifndef BOOST_NO_CXX11_DEFAULTED_FUNCTIONS
+ optional ( optional && rhs ) = default;
+#else
optional ( optional && rhs )
BOOST_NOEXCEPT_IF(::boost::is_nothrow_move_constructible::value)
: base( boost::move(rhs) )
{}
+#endif
#endif
@@ -959,21 +1029,30 @@ class optional : public optional_detail::optional_base
// Assigns from another optional (deep-copies the rhs value)
// Basic Guarantee: If T::T( T const& ) throws, this is left UNINITIALIZED
// (NOTE: On BCB, this operator is not actually called and left is left UNMODIFIED in case of a throw)
+#ifndef BOOST_NO_CXX11_DEFAULTED_FUNCTIONS
+ optional& operator= ( optional const& rhs ) = default;
+#else
optional& operator= ( optional const& rhs )
{
this->assign( static_cast(rhs) ) ;
return *this ;
}
+#endif
#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
// Assigns from another optional (deep-moves the rhs value)
+#ifndef BOOST_NO_CXX11_DEFAULTED_FUNCTIONS
+ optional& operator= ( optional && ) = default;
+#else
optional& operator= ( optional && rhs )
BOOST_NOEXCEPT_IF(::boost::is_nothrow_move_constructible::value && ::boost::is_nothrow_move_assignable::value)
{
this->assign( static_cast(rhs) ) ;
return *this ;
}
-#endif
+#endif
+
+#endif // BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES
#ifndef BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX
diff --git a/test/Jamfile.v2 b/test/Jamfile.v2
index d081abc..fd3c7e2 100644
--- a/test/Jamfile.v2
+++ b/test/Jamfile.v2
@@ -1,7 +1,7 @@
# Boost.Optional Library test Jamfile
#
# Copyright (C) 2003, Fernando Luis Cacciola Carballal.
-# Copyright (C) 2014 - 2016 Andrzej Krzemienski
+# Copyright (C) 2014 - 2017 Andrzej Krzemienski
#
# Use, modification, and distribution is subject to the Boost Software
# License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
@@ -66,6 +66,7 @@ import testing ;
[ compile-fail optional_test_fail_io_without_io.cpp ]
[ compile-fail optional_test_fail_none_io_without_io.cpp ]
[ compile-fail optional_test_fail_convert_assign_of_enums.cpp ]
+ [ run optional_test_static_properties.cpp ]
[ run optional_xconfig_NO_PROPER_ASSIGN_FROM_CONST_INT_pass.cpp ]
[ run-fail optional_xconfig_NO_PROPER_ASSIGN_FROM_CONST_INT_fail.cpp ]
[ run optional_xconfig_NO_PROPER_CONVERT_FROM_CONST_INT_pass.cpp ]
diff --git a/test/optional_test_static_properties.cpp b/test/optional_test_static_properties.cpp
new file mode 100644
index 0000000..02695c7
--- /dev/null
+++ b/test/optional_test_static_properties.cpp
@@ -0,0 +1,140 @@
+// Copyright (C) 2017 Andrzej Krzemienski.
+//
+// Use, modification, and distribution is subject to the Boost Software
+// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+//
+// See http://www.boost.org/lib/optional for documentation.
+//
+// You are welcome to contact the author at:
+// akrzemi1@gmail.com
+
+#include "boost/optional/optional.hpp"
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
+#include "boost/core/lightweight_test.hpp"
+#include "boost/core/lightweight_test_trait.hpp"
+#include "boost/type_traits/is_base_of.hpp"
+
+#ifndef BOOST_NO_CXX11_DEFAULTED_FUNCTIONS
+
+#if (defined BOOST_HAS_TRIVIAL_MOVE_ASSIGN) && (defined BOOST_HAS_TRIVIAL_MOVE_CONSTRUCTOR) && (defined BOOST_HAS_TRIVIAL_CONSTRUCTOR) && (defined BOOST_HAS_TRIVIAL_COPY) && (defined BOOST_HAS_TRIVIAL_ASSIGN) && (defined BOOST_HAS_TRIVIAL_DESTRUCTOR)
+#else
+# define BOOST_OPTIONAL_NO_TRIVIALITY_DETECTION
+#endif
+
+struct PrivDefault
+{
+ private: PrivDefault() {}
+};
+
+struct CustDefault
+{
+ CustDefault() {}
+};
+
+struct CustomizedTrivial
+{
+ CustomizedTrivial() {}
+};
+
+namespace boost { namespace optional_config {
+
+template <> struct is_type_trivial : boost::true_type {};
+
+}}
+
+struct CustDtor
+{
+ ~CustDtor() {}
+};
+
+struct NoDefault
+{
+ explicit NoDefault(int) {}
+};
+
+struct Empty {};
+
+template
+struct Aggregate { T t; U u; };
+
+struct CustAssign
+{
+ CustAssign& operator=(CustAssign const&) { return *this; }
+};
+
+struct CustMove
+{
+ CustMove(CustMove &&) {}
+};
+
+void test_type_traits()
+{
+ // this only tests if type traits are implemented correctly
+ BOOST_TEST_TRAIT_TRUE(( boost::optional_config::is_type_trivial ));
+ BOOST_TEST_TRAIT_TRUE(( boost::optional_config::is_type_trivial ));
+ BOOST_TEST_TRAIT_TRUE(( boost::optional_config::is_type_trivial ));
+ BOOST_TEST_TRAIT_TRUE(( boost::optional_config::is_type_trivial > ));
+ BOOST_TEST_TRAIT_TRUE(( boost::optional_config::is_type_trivial, double> > ));
+
+ BOOST_TEST_TRAIT_TRUE(( boost::optional_config::is_type_trivial ));
+
+ BOOST_TEST_TRAIT_FALSE(( boost::optional_config::is_type_trivial ));
+ BOOST_TEST_TRAIT_FALSE(( boost::optional_config::is_type_trivial ));
+ BOOST_TEST_TRAIT_FALSE(( boost::optional_config::is_type_trivial ));
+ BOOST_TEST_TRAIT_FALSE(( boost::optional_config::is_type_trivial > ));
+
+ BOOST_TEST_TRAIT_FALSE(( boost::optional_config::is_type_trivial ));
+ BOOST_TEST_TRAIT_FALSE(( boost::optional_config::is_type_trivial ));
+ BOOST_TEST_TRAIT_FALSE(( boost::optional_config::is_type_trivial ));
+ BOOST_TEST_TRAIT_FALSE(( boost::optional_config::is_type_trivial > ));
+
+ BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable ));
+ BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable ));
+ BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable ));
+ BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable > ));
+ BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable, double> > ));
+
+#ifndef BOOST_OPTIONAL_NO_TRIVIALITY_DETECTION
+ BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable ));
+ BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable ));
+ BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable ));
+ BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable > ));
+#endif
+
+ BOOST_TEST_TRAIT_FALSE(( boost::optional_detail::is_type_trivially_copyable ));
+ BOOST_TEST_TRAIT_FALSE(( boost::optional_detail::is_type_trivially_copyable ));
+ BOOST_TEST_TRAIT_FALSE(( boost::optional_detail::is_type_trivially_copyable ));
+ BOOST_TEST_TRAIT_FALSE(( boost::optional_detail::is_type_trivially_copyable > ));
+}
+
+void test_trivial_copyability()
+{
+ BOOST_TEST_TRAIT_TRUE((boost::is_base_of, boost::optional > ));
+ BOOST_TEST_TRAIT_TRUE((boost::is_base_of, boost::optional > ));
+ BOOST_TEST_TRAIT_TRUE((boost::is_base_of, boost::optional > ));
+
+#ifndef BOOST_OPTIONAL_NO_TRIVIALITY_DETECTION
+ BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable > ));
+ BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable > ));
+ BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable > ));
+ BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable > ));
+ BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable > > ));
+ BOOST_TEST_TRAIT_TRUE(( boost::optional_detail::is_type_trivially_copyable, double> > > ));
+#endif
+}
+
+#endif
+
+int main()
+{
+#ifndef BOOST_NO_CXX11_DEFAULTED_FUNCTIONS
+ test_type_traits();
+ test_trivial_copyability();
+#endif
+ return boost::report_errors();
+}
\ No newline at end of file