diff --git a/include/boost/optional/optional.hpp b/include/boost/optional/optional.hpp index ff1a16c..6a843b2 100644 --- a/include/boost/optional/optional.hpp +++ b/include/boost/optional/optional.hpp @@ -56,6 +56,21 @@ #include #else namespace boost { + +namespace optional_ns { + +class in_place_init_t {}; // a tag for in-place initialization +const in_place_init_t in_place_init; // of contained value + +class in_place_init_if_t {}; // a tag for conditional in-place +const in_place_init_if_t in_place_init_if; // init of contained value + +} // namespace optional_ns + +using optional_ns::in_place_init_t; +using optional_ns::in_place_init; +using optional_ns::in_place_init_if_t; +using optional_ns::in_place_init_if; namespace optional_detail { @@ -338,51 +353,177 @@ class optional_base : public optional_tag #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 ) + { + ::new (m_storage.address()) value_type( boost::forward(args)... ) ; + m_initialized = true ; + } + template void emplace_assign ( Args&&... args ) - { - destroy(); - ::new (m_storage.address()) value_type( boost::forward(args)... ); - m_initialized = true ; - } + { + destroy(); + construct(in_place_init, boost::forward(args)...); + } + + template + explicit optional_base ( in_place_init_t, Args&&... args ) + : + m_initialized(false) + { + construct(in_place_init, boost::forward(args)...); + } + + template + explicit 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 emplace_assign ( Arg&& arg ) + void construct ( in_place_init_t, Arg&& arg ) { - destroy(); ::new (m_storage.address()) value_type( boost::forward(arg) ); m_initialized = true ; } - void emplace_assign () + void construct ( in_place_init_t ) { - destroy(); ::new (m_storage.address()) value_type(); m_initialized = true ; } -#else + template - void emplace_assign ( const Arg& arg ) + void emplace_assign ( Arg&& arg ) { destroy(); + construct(in_place_init, boost::forward(arg)) ; + } + + void emplace_assign () + { + destroy(); + construct(in_place_init) ; + } + + explicit optional_base ( in_place_init_t, Arg&& args ) + : + m_initialized(false) + { + construct(in_place_init, boost::forward(arg)); + } + + explicit optional_base ( in_place_init_t ) + : + m_initialized(false) + { + construct(in_place_init); + } + + explicit optional_base ( in_place_init_if_t, bool cond, Arg&& args ) + : + m_initialized(false) + { + if ( cond ) + construct(in_place_init, boost::forward(arg)); + } + + explicit 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 ) + { ::new (m_storage.address()) value_type( arg ); m_initialized = true ; } + template + void construct ( in_place_init_t, Arg& arg ) + { + ::new (m_storage.address()) value_type( arg ); + m_initialized = true ; + } + + void construct ( in_place_init_t ) + { + ::new (m_storage.address()) value_type(); + m_initialized = true ; + } + + template + void emplace_assign ( const Arg& arg ) + { + destroy(); + construct(in_place_init, arg); + } + template void emplace_assign ( Arg& arg ) - { - destroy(); - ::new (m_storage.address()) value_type( arg ); - m_initialized = true ; - } + { + destroy(); + construct(in_place_init, arg); + } void emplace_assign () - { - destroy(); - ::new (m_storage.address()) value_type(); - m_initialized = true ; - } + { + destroy(); + construct(in_place_init); + } + + template + explicit optional_base ( in_place_init_t, const Arg& arg ) + : m_initialized(false) + { + construct(in_place_init, arg); + } + + template + explicit optional_base ( in_place_init_t, Arg& arg ) + : m_initialized(false) + { + construct(in_place_init, arg); + } + + explicit optional_base ( in_place_init_t ) + : m_initialized(false) + { + construct(in_place_init); + } + + template + explicit optional_base ( in_place_init_if_t, bool cond, const Arg& arg ) + : m_initialized(false) + { + if ( cond ) + construct(in_place_init, arg); + } + + template + explicit optional_base ( in_place_init_if_t, bool cond, Arg& arg ) + : m_initialized(false) + { + if ( cond ) + construct(in_place_init, arg); + } + + explicit 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 @@ -820,9 +961,20 @@ class optional : public optional_detail::optional_base // upon exception *this is always uninitialized template void emplace ( Args&&... args ) - { - this->emplace_assign( boost::forward(args)... ); - } + { + this->emplace_assign( boost::forward(args)... ); + } + + template + explicit optional ( in_place_init_t, Args&&... args ) + : base( in_place_init, boost::forward(args)... ) + {} + + template + explicit optional ( in_place_init_if_t, bool cond, Args&&... args ) + : base( in_place_init_if, cond, boost::forward(args)... ) + {} + #elif (!defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES) template void emplace ( Arg&& arg ) @@ -834,6 +986,24 @@ class optional : public optional_detail::optional_base { this->emplace_assign(); } + + template + explicit optional ( in_place_init_t, Args&& args ) + : base( in_place_init, boost::forward(args) ) + {} + + explicit optional ( in_place_init_t ) + : base( in_place_init ) + {} + + template + explicit optional ( in_place_init_if_t, bool cond, Args&& args ) + : base( in_place_init_if, cond, boost::forward(args) ) + {} + + explicit optional ( in_place_init_if_t, bool cond ) + : base( in_place_init_if, cond ) + {} #else template void emplace ( const Arg& arg ) @@ -851,6 +1021,34 @@ class optional : public optional_detail::optional_base { this->emplace_assign(); } + + template + explicit optional ( in_place_init_t, const Arg& arg ) + : base( in_place_init, arg ) + {} + + template + explicit optional ( in_place_init_t, Arg& arg ) + : base( in_place_init, arg ) + {} + + explicit optional ( in_place_init_t ) + : base( in_place_init ) + {} + + template + explicit optional ( in_place_init_if_t, bool cond, const Arg& arg ) + : base( in_place_init_if, cond, arg ) + {} + + template + explicit optional ( in_place_init_if_t, bool cond, Arg& arg ) + : base( in_place_init_if, cond, arg ) + {} + + explicit optional ( in_place_init_if_t, bool cond ) + : base( in_place_init_if, cond ) + {} #endif void swap( optional & arg ) diff --git a/test/optional_test_emplace.cpp b/test/optional_test_emplace.cpp index 1877a54..36972d3 100644 --- a/test/optional_test_emplace.cpp +++ b/test/optional_test_emplace.cpp @@ -23,6 +23,8 @@ using boost::optional; using boost::none; +using boost::in_place_init; +using boost::in_place_init_if; #if (!defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES) && (!defined BOOST_NO_CXX11_VARIADIC_TEMPLATES) @@ -87,6 +89,109 @@ void test_emplace() BOOST_TEST(7 == o->which_ctor); } +void test_in_place_ctor() +{ + int i = 0; + double d = 0.0; + const std::string cs; + std::string ms; + + { + optional o (in_place_init); + BOOST_TEST(o); + BOOST_TEST(0 == o->which_ctor); + } + { + optional o (in_place_init, i, 2.0); + BOOST_TEST(o); + BOOST_TEST(1 == o->which_ctor); + } + { + optional o (in_place_init, 1, d); + BOOST_TEST(o); + BOOST_TEST(2 == o->which_ctor); + } + { + optional o (in_place_init, 1, 2.0); + BOOST_TEST(o); + BOOST_TEST(3 == o->which_ctor); + } + { + optional o (in_place_init, i, d); + BOOST_TEST(o); + BOOST_TEST(4 == o->which_ctor); + } + { + optional o (in_place_init, cs); + BOOST_TEST(o); + BOOST_TEST(5 == o->which_ctor); + } + { + optional o (in_place_init, ms); + BOOST_TEST(o); + BOOST_TEST(6 == o->which_ctor); + } + { + optional o (in_place_init, std::string()); + BOOST_TEST(o); + BOOST_TEST(7 == o->which_ctor); + } +} + +void test_in_place_if_ctor() +{ + int i = 0; + double d = 0.0; + const std::string cs; + std::string ms; + + { + optional o (in_place_init_if, true); + BOOST_TEST(o); + BOOST_TEST(0 == o->which_ctor); + } + { + optional o (in_place_init_if, true, i, 2.0); + BOOST_TEST(o); + BOOST_TEST(1 == o->which_ctor); + } + { + optional o (in_place_init_if, true, 1, d); + BOOST_TEST(o); + BOOST_TEST(2 == o->which_ctor); + } + { + optional o (in_place_init_if, true, 1, 2.0); + BOOST_TEST(o); + BOOST_TEST(3 == o->which_ctor); + } + { + optional o (in_place_init_if, true, i, d); + BOOST_TEST(o); + BOOST_TEST(4 == o->which_ctor); + } + { + optional o (in_place_init_if, true, cs); + BOOST_TEST(o); + BOOST_TEST(5 == o->which_ctor); + } + { + optional o (in_place_init_if, true, ms); + BOOST_TEST(o); + BOOST_TEST(6 == o->which_ctor); + } + { + optional o (in_place_init_if, true, std::string()); + BOOST_TEST(o); + BOOST_TEST(7 == o->which_ctor); + } + + { + optional o (in_place_init_if, false, 1, 2.0); + BOOST_TEST(!o); + } +} + #endif @@ -112,6 +217,24 @@ void test_no_moves_on_emplacement() BOOST_TEST(false); } } + +void test_no_moves_on_in_place_ctor() +{ + try { + optional o (in_place_init, 1); + BOOST_TEST(o); + + optional p (in_place_init_if, true, 1); + BOOST_TEST(p); + + optional q (in_place_init_if, false, 1); + BOOST_TEST(!q); + } + catch (...) { + BOOST_TEST(false); + } +} + #endif struct Thrower @@ -158,6 +281,7 @@ void test_no_assignment_on_emplacement() } namespace no_rvalue_refs { + class Guard { public: @@ -188,19 +312,78 @@ void test_emplace() BOOST_TEST(o); BOOST_TEST(6 == o->which_ctor); } -} + +void test_in_place_ctor() +{ + const std::string cs; + std::string ms; + + { + optional o (in_place_init); + BOOST_TEST(o); + BOOST_TEST(0 == o->which_ctor); + } + { + optional o (in_place_init, cs); + BOOST_TEST(o); + BOOST_TEST(5 == o->which_ctor); + } + { + optional o (in_place_init, ms); + BOOST_TEST(o); + BOOST_TEST(6 == o->which_ctor); + } +} + +void test_in_place_if_ctor() +{ + const std::string cs; + std::string ms; + + { + optional n (in_place_init_if, false); + BOOST_TEST(!n); + + optional o (in_place_init_if, true); + BOOST_TEST(o); + BOOST_TEST(0 == o->which_ctor); + } + { + optional n (in_place_init_if, false, cs); + BOOST_TEST(!n); + + optional o (in_place_init_if, true, cs); + BOOST_TEST(o); + BOOST_TEST(5 == o->which_ctor); + } + { + optional n (in_place_init_if, false, ms); + BOOST_TEST(!n); + + optional o (in_place_init_if, true, ms); + BOOST_TEST(o); + BOOST_TEST(6 == o->which_ctor); + } +} + +} // namespace no_rvalue_ref int main() { #if (!defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES) && (!defined BOOST_NO_CXX11_VARIADIC_TEMPLATES) test_emplace(); + test_in_place_ctor(); + test_in_place_if_ctor(); #endif #if (!defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES) test_no_moves_on_emplacement(); + test_no_moves_on_in_place_ctor(); #endif test_clear_on_throw(); test_no_assignment_on_emplacement(); no_rvalue_refs::test_emplace(); + no_rvalue_refs::test_in_place_ctor(); + no_rvalue_refs::test_in_place_if_ctor(); return boost::report_errors(); }