added in_place constructors

This commit is contained in:
Andrzej Krzemienski
2016-10-27 01:08:17 +02:00
parent a710a23102
commit eb9ea1f72d
2 changed files with 406 additions and 25 deletions

View File

@ -56,6 +56,21 @@
#include <boost/optional/detail/old_optional_implementation.hpp> #include <boost/optional/detail/old_optional_implementation.hpp>
#else #else
namespace boost { 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 { 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) #if (!defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES) && (!defined BOOST_NO_CXX11_VARIADIC_TEMPLATES)
// Constructs in-place // Constructs in-place
// upon exception *this is always uninitialized // upon exception *this is always uninitialized
template<class... Args>
void construct ( in_place_init_t, Args&&... args )
{
::new (m_storage.address()) value_type( boost::forward<Args>(args)... ) ;
m_initialized = true ;
}
template<class... Args> template<class... Args>
void emplace_assign ( Args&&... args ) void emplace_assign ( Args&&... args )
{ {
destroy(); destroy();
::new (m_storage.address()) value_type( boost::forward<Args>(args)... ); construct(in_place_init, boost::forward<Args>(args)...);
m_initialized = true ; }
}
template<class... Args>
explicit optional_base ( in_place_init_t, Args&&... args )
:
m_initialized(false)
{
construct(in_place_init, boost::forward<Args>(args)...);
}
template<class... Args>
explicit optional_base ( in_place_init_if_t, bool cond, Args&&... args )
:
m_initialized(false)
{
if ( cond )
construct(in_place_init, boost::forward<Args>(args)...);
}
#elif (!defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES) #elif (!defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES)
template<class Arg> template<class Arg>
void emplace_assign ( Arg&& arg ) void construct ( in_place_init_t, Arg&& arg )
{ {
destroy();
::new (m_storage.address()) value_type( boost::forward<Arg>(arg) ); ::new (m_storage.address()) value_type( boost::forward<Arg>(arg) );
m_initialized = true ; m_initialized = true ;
} }
void emplace_assign () void construct ( in_place_init_t )
{ {
destroy();
::new (m_storage.address()) value_type(); ::new (m_storage.address()) value_type();
m_initialized = true ; m_initialized = true ;
} }
#else
template<class Arg> template<class Arg>
void emplace_assign ( const Arg& arg ) void emplace_assign ( Arg&& arg )
{ {
destroy(); destroy();
construct(in_place_init, boost::forward<Arg>(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>(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>(arg));
}
explicit optional_base ( in_place_init_if_t, bool cond )
:
m_initialized(false)
{
if ( cond )
construct(in_place_init);
}
#else
template<class Arg>
void construct ( in_place_init_t, const Arg& arg )
{
::new (m_storage.address()) value_type( arg ); ::new (m_storage.address()) value_type( arg );
m_initialized = true ; m_initialized = true ;
} }
template<class Arg>
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<class Arg>
void emplace_assign ( const Arg& arg )
{
destroy();
construct(in_place_init, arg);
}
template<class Arg> template<class Arg>
void emplace_assign ( Arg& arg ) void emplace_assign ( Arg& arg )
{ {
destroy(); destroy();
::new (m_storage.address()) value_type( arg ); construct(in_place_init, arg);
m_initialized = true ; }
}
void emplace_assign () void emplace_assign ()
{ {
destroy(); destroy();
::new (m_storage.address()) value_type(); construct(in_place_init);
m_initialized = true ; }
}
template<class Arg>
explicit optional_base ( in_place_init_t, const Arg& arg )
: m_initialized(false)
{
construct(in_place_init, arg);
}
template<class Arg>
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<class Arg>
explicit optional_base ( in_place_init_if_t, bool cond, const Arg& arg )
: m_initialized(false)
{
if ( cond )
construct(in_place_init, arg);
}
template<class Arg>
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 #endif
#ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT #ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT
@ -820,9 +961,20 @@ class optional : public optional_detail::optional_base<T>
// upon exception *this is always uninitialized // upon exception *this is always uninitialized
template<class... Args> template<class... Args>
void emplace ( Args&&... args ) void emplace ( Args&&... args )
{ {
this->emplace_assign( boost::forward<Args>(args)... ); this->emplace_assign( boost::forward<Args>(args)... );
} }
template<class... Args>
explicit optional ( in_place_init_t, Args&&... args )
: base( in_place_init, boost::forward<Args>(args)... )
{}
template<class... Args>
explicit optional ( in_place_init_if_t, bool cond, Args&&... args )
: base( in_place_init_if, cond, boost::forward<Args>(args)... )
{}
#elif (!defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES) #elif (!defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES)
template<class Arg> template<class Arg>
void emplace ( Arg&& arg ) void emplace ( Arg&& arg )
@ -834,6 +986,24 @@ class optional : public optional_detail::optional_base<T>
{ {
this->emplace_assign(); this->emplace_assign();
} }
template<class Args>
explicit optional ( in_place_init_t, Args&& args )
: base( in_place_init, boost::forward<Args>(args) )
{}
explicit optional ( in_place_init_t )
: base( in_place_init )
{}
template<class Args>
explicit optional ( in_place_init_if_t, bool cond, Args&& args )
: base( in_place_init_if, cond, boost::forward<Args>(args) )
{}
explicit optional ( in_place_init_if_t, bool cond )
: base( in_place_init_if, cond )
{}
#else #else
template<class Arg> template<class Arg>
void emplace ( const Arg& arg ) void emplace ( const Arg& arg )
@ -851,6 +1021,34 @@ class optional : public optional_detail::optional_base<T>
{ {
this->emplace_assign(); this->emplace_assign();
} }
template<class Arg>
explicit optional ( in_place_init_t, const Arg& arg )
: base( in_place_init, arg )
{}
template<class Arg>
explicit optional ( in_place_init_t, Arg& arg )
: base( in_place_init, arg )
{}
explicit optional ( in_place_init_t )
: base( in_place_init )
{}
template<class Arg>
explicit optional ( in_place_init_if_t, bool cond, const Arg& arg )
: base( in_place_init_if, cond, arg )
{}
template<class Arg>
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 #endif
void swap( optional & arg ) void swap( optional & arg )

View File

@ -23,6 +23,8 @@
using boost::optional; using boost::optional;
using boost::none; 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) #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); 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<Guard> o (in_place_init);
BOOST_TEST(o);
BOOST_TEST(0 == o->which_ctor);
}
{
optional<Guard> o (in_place_init, i, 2.0);
BOOST_TEST(o);
BOOST_TEST(1 == o->which_ctor);
}
{
optional<Guard> o (in_place_init, 1, d);
BOOST_TEST(o);
BOOST_TEST(2 == o->which_ctor);
}
{
optional<Guard> o (in_place_init, 1, 2.0);
BOOST_TEST(o);
BOOST_TEST(3 == o->which_ctor);
}
{
optional<Guard> o (in_place_init, i, d);
BOOST_TEST(o);
BOOST_TEST(4 == o->which_ctor);
}
{
optional<Guard> o (in_place_init, cs);
BOOST_TEST(o);
BOOST_TEST(5 == o->which_ctor);
}
{
optional<Guard> o (in_place_init, ms);
BOOST_TEST(o);
BOOST_TEST(6 == o->which_ctor);
}
{
optional<Guard> 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<Guard> o (in_place_init_if, true);
BOOST_TEST(o);
BOOST_TEST(0 == o->which_ctor);
}
{
optional<Guard> o (in_place_init_if, true, i, 2.0);
BOOST_TEST(o);
BOOST_TEST(1 == o->which_ctor);
}
{
optional<Guard> o (in_place_init_if, true, 1, d);
BOOST_TEST(o);
BOOST_TEST(2 == o->which_ctor);
}
{
optional<Guard> o (in_place_init_if, true, 1, 2.0);
BOOST_TEST(o);
BOOST_TEST(3 == o->which_ctor);
}
{
optional<Guard> o (in_place_init_if, true, i, d);
BOOST_TEST(o);
BOOST_TEST(4 == o->which_ctor);
}
{
optional<Guard> o (in_place_init_if, true, cs);
BOOST_TEST(o);
BOOST_TEST(5 == o->which_ctor);
}
{
optional<Guard> o (in_place_init_if, true, ms);
BOOST_TEST(o);
BOOST_TEST(6 == o->which_ctor);
}
{
optional<Guard> o (in_place_init_if, true, std::string());
BOOST_TEST(o);
BOOST_TEST(7 == o->which_ctor);
}
{
optional<Guard> o (in_place_init_if, false, 1, 2.0);
BOOST_TEST(!o);
}
}
#endif #endif
@ -112,6 +217,24 @@ void test_no_moves_on_emplacement()
BOOST_TEST(false); BOOST_TEST(false);
} }
} }
void test_no_moves_on_in_place_ctor()
{
try {
optional<ThrowOnMove> o (in_place_init, 1);
BOOST_TEST(o);
optional<ThrowOnMove> p (in_place_init_if, true, 1);
BOOST_TEST(p);
optional<ThrowOnMove> q (in_place_init_if, false, 1);
BOOST_TEST(!q);
}
catch (...) {
BOOST_TEST(false);
}
}
#endif #endif
struct Thrower struct Thrower
@ -158,6 +281,7 @@ void test_no_assignment_on_emplacement()
} }
namespace no_rvalue_refs { namespace no_rvalue_refs {
class Guard class Guard
{ {
public: public:
@ -188,19 +312,78 @@ void test_emplace()
BOOST_TEST(o); BOOST_TEST(o);
BOOST_TEST(6 == o->which_ctor); BOOST_TEST(6 == o->which_ctor);
} }
}
void test_in_place_ctor()
{
const std::string cs;
std::string ms;
{
optional<Guard> o (in_place_init);
BOOST_TEST(o);
BOOST_TEST(0 == o->which_ctor);
}
{
optional<Guard> o (in_place_init, cs);
BOOST_TEST(o);
BOOST_TEST(5 == o->which_ctor);
}
{
optional<Guard> 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<Guard> n (in_place_init_if, false);
BOOST_TEST(!n);
optional<Guard> o (in_place_init_if, true);
BOOST_TEST(o);
BOOST_TEST(0 == o->which_ctor);
}
{
optional<Guard> n (in_place_init_if, false, cs);
BOOST_TEST(!n);
optional<Guard> o (in_place_init_if, true, cs);
BOOST_TEST(o);
BOOST_TEST(5 == o->which_ctor);
}
{
optional<Guard> n (in_place_init_if, false, ms);
BOOST_TEST(!n);
optional<Guard> o (in_place_init_if, true, ms);
BOOST_TEST(o);
BOOST_TEST(6 == o->which_ctor);
}
}
} // namespace no_rvalue_ref
int main() int main()
{ {
#if (!defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES) && (!defined BOOST_NO_CXX11_VARIADIC_TEMPLATES) #if (!defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES) && (!defined BOOST_NO_CXX11_VARIADIC_TEMPLATES)
test_emplace(); test_emplace();
test_in_place_ctor();
test_in_place_if_ctor();
#endif #endif
#if (!defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES) #if (!defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES)
test_no_moves_on_emplacement(); test_no_moves_on_emplacement();
test_no_moves_on_in_place_ctor();
#endif #endif
test_clear_on_throw(); test_clear_on_throw();
test_no_assignment_on_emplacement(); test_no_assignment_on_emplacement();
no_rvalue_refs::test_emplace(); no_rvalue_refs::test_emplace();
no_rvalue_refs::test_in_place_ctor();
no_rvalue_refs::test_in_place_if_ctor();
return boost::report_errors(); return boost::report_errors();
} }