diff --git a/include/boost/system/result.hpp b/include/boost/system/result.hpp index 08eb899..98fb55b 100644 --- a/include/boost/system/result.hpp +++ b/include/boost/system/result.hpp @@ -649,6 +649,224 @@ template std::basic_ostream& operator<<( st return os; } +// result + +namespace detail +{ + +template struct reference_to_temporary: std::integral_constant::value || + !std::is_convertible::type*, U*>::value +> {}; + +} // namespace detail + +template class result +{ +private: + + variant2::variant v_; + +public: + + using value_type = U&; + using error_type = E; + + static constexpr in_place_value_t in_place_value{}; + static constexpr in_place_error_t in_place_error{}; + +public: + + // constructors + + // implicit, value + template::value && + !detail::reference_to_temporary::value && + !std::is_convertible::value, int>::type = 0> + constexpr result( A&& a ) + noexcept( std::is_nothrow_constructible::value ) + : v_( in_place_value, &static_cast( std::forward(a) ) ) + { + } + + // implicit, error + template::value && + !std::is_convertible::value, int>::type = 0> + constexpr result( A&& a ) + noexcept( std::is_nothrow_constructible::value ) + : v_( in_place_error, std::forward(a) ) + { + } + + // explicit, value + template::value && + !std::is_convertible::value && + !detail::reference_to_temporary::value && + !detail::is_constructible::value + >::type> + explicit constexpr result( A&& a ) + noexcept( std::is_nothrow_constructible::value ) + : v_( in_place_value, &static_cast( std::forward(a) ) ) + { + } + + // explicit, error + template::value && + detail::is_constructible::value && + sizeof...(A) >= 1 + >::type> + explicit constexpr result( A&&... a ) + noexcept( std::is_nothrow_constructible::value ) + : v_( in_place_error, std::forward(a)... ) + { + } + + // tagged, value + template::value + >::type> + constexpr result( in_place_value_t, A&& a ) + noexcept( std::is_nothrow_constructible::value ) + : v_( in_place_value, &static_cast( std::forward(a) ) ) + { + } + + // tagged, error + template::value + >::type> + constexpr result( in_place_error_t, A&&... a ) + noexcept( std::is_nothrow_constructible::value ) + : v_( in_place_error, std::forward(a)... ) + { + } + + // converting + template::value && + !detail::reference_to_temporary::value && + std::is_convertible::value && + !std::is_convertible const&, U&>::value + >::type> + BOOST_CXX14_CONSTEXPR result( result const& r2 ) + noexcept( + std::is_nothrow_constructible::value && + std::is_nothrow_constructible::value && + std::is_nothrow_default_constructible::value && + std::is_nothrow_copy_constructible::value ) + : v_( in_place_error, r2.error() ) + { + if( r2 ) + { + this->emplace( *r2 ); + } + } + + // queries + + constexpr bool has_value() const noexcept + { + return v_.index() == 0; + } + + constexpr bool has_error() const noexcept + { + return v_.index() == 1; + } + + constexpr explicit operator bool() const noexcept + { + return v_.index() == 0; + } + + // checked value access + + BOOST_CXX14_CONSTEXPR U& value( boost::source_location const& loc = BOOST_CURRENT_LOCATION ) const + { + if( has_value() ) + { + return *variant2::unsafe_get<0>( v_ ); + } + else + { + throw_exception_from_error( variant2::unsafe_get<1>( v_ ), loc ); + } + } + + // unchecked value access + + BOOST_CXX14_CONSTEXPR U* operator->() const noexcept + { + return has_value()? variant2::unsafe_get<0>( v_ ): 0; + } + + BOOST_CXX14_CONSTEXPR U& operator*() const noexcept + { + U* p = operator->(); + + BOOST_ASSERT( p != 0 ); + + return *p; + } + + // error access + + constexpr E error() const & + noexcept( std::is_nothrow_default_constructible::value && std::is_nothrow_copy_constructible::value ) + { + return has_error()? variant2::unsafe_get<1>( v_ ): E(); + } + + BOOST_CXX14_CONSTEXPR E error() && + noexcept( std::is_nothrow_default_constructible::value && std::is_nothrow_move_constructible::value ) + { + return has_error()? std::move( variant2::unsafe_get<1>( v_ ) ): E(); + } + + // emplace + + template::value && + !detail::reference_to_temporary::value + >::type> + BOOST_CXX14_CONSTEXPR U& emplace( A&& a ) + { + return *v_.template emplace<0>( &static_cast( a ) ); + } + + // swap + + BOOST_CXX14_CONSTEXPR void swap( result& r ) + noexcept( noexcept( v_.swap( r.v_ ) ) ) + { + v_.swap( r.v_ ); + } + + friend BOOST_CXX14_CONSTEXPR void swap( result & r1, result & r2 ) + noexcept( noexcept( r1.swap( r2 ) ) ) + { + r1.swap( r2 ); + } + + // equality + + friend constexpr bool operator==( result const & r1, result const & r2 ) + noexcept( noexcept( r1 && r2? *r1 == *r2: r1.v_ == r2.v_ ) ) + { + return r1 && r2? *r1 == *r2: r1.v_ == r2.v_; + } + + friend constexpr bool operator!=( result const & r1, result const & r2 ) + noexcept( noexcept( !( r1 == r2 ) ) ) + { + return !( r1 == r2 ); + } +}; + } // namespace system } // namespace boost diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 7bc6d67..bc4b728 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -164,3 +164,6 @@ boost_test(TYPE run SOURCES result_error_construct4.cpp) boost_test(TYPE run SOURCES result_value_construct4.cpp) boost_test(TYPE run SOURCES result_value_construct5.cpp) boost_test(TYPE run SOURCES result_error_move.cpp) +boost_test(TYPE run SOURCES result_value_construct6.cpp) +boost_test(TYPE run SOURCES result_value_construct7.cpp) +boost_test(TYPE run SOURCES result_error_construct5.cpp) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 139bb23..a27aec9 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -194,3 +194,6 @@ run result_error_construct4.cpp : : : $(CPP11) ; run result_value_construct4.cpp : : : $(CPP11) ; run result_value_construct5.cpp : : : $(CPP11) ; run result_error_move.cpp : : : $(CPP11) ; +run result_value_construct6.cpp : : : $(CPP11) ; +run result_value_construct7.cpp : : : $(CPP11) ; +run result_error_construct5.cpp : : : $(CPP11) ; diff --git a/test/result_convert_construct.cpp b/test/result_convert_construct.cpp index be6faad..47c9c78 100644 --- a/test/result_convert_construct.cpp +++ b/test/result_convert_construct.cpp @@ -181,6 +181,34 @@ int main() BOOST_TEST_EQ( X::instances, 0 ); + // + + { + int x = 5; + + result r( x ); + result r2 = r; + + BOOST_TEST( r2 ) && BOOST_TEST_EQ( *r2, 5 ); + } + + { + int x = 6; + + result const r( x ); + result r2 = r; + + BOOST_TEST( r2 ) && BOOST_TEST_EQ( *r2, 6 ); + } + + { + int x = 7; + + result r2 = result( x ); + + BOOST_TEST( r2 ) && BOOST_TEST_EQ( *r2, 7 ); + } + { BOOST_TEST_TRAIT_TRUE((std::is_constructible, result>)); BOOST_TEST_TRAIT_TRUE((std::is_convertible, result>)); @@ -196,6 +224,18 @@ int main() BOOST_TEST_TRAIT_FALSE((std::is_constructible, result>)); BOOST_TEST_TRAIT_FALSE((std::is_convertible, result>)); + + BOOST_TEST_TRAIT_TRUE((std::is_constructible, result>)); + BOOST_TEST_TRAIT_TRUE((std::is_convertible, result>)); + + BOOST_TEST_TRAIT_FALSE((std::is_constructible, result>)); + BOOST_TEST_TRAIT_FALSE((std::is_convertible, result>)); + + BOOST_TEST_TRAIT_FALSE((std::is_constructible, result>)); + BOOST_TEST_TRAIT_FALSE((std::is_convertible, result>)); + + BOOST_TEST_TRAIT_FALSE((std::is_constructible, result>)); + BOOST_TEST_TRAIT_FALSE((std::is_convertible, result>)); } return boost::report_errors(); diff --git a/test/result_copy_assign.cpp b/test/result_copy_assign.cpp index d80b0dc..6bc41f8 100644 --- a/test/result_copy_assign.cpp +++ b/test/result_copy_assign.cpp @@ -682,5 +682,151 @@ int main() BOOST_TEST_EQ( r, r2 ); } + // reference + + { + int x1 = 1; + int x2 = 2; + + result r1( x1 ); + result r2( x2 ); + + r2 = r1; + + BOOST_TEST_EQ( x1, 1 ); + BOOST_TEST_EQ( x2, 2 ); + + BOOST_TEST_EQ( r1, r2 ); + BOOST_TEST_EQ( &*r1, &*r2 ); + } + + { + int const x1 = 1; + int const x2 = 2; + + result r1( x1 ); + result r2( x2 ); + + r2 = r1; + + BOOST_TEST_EQ( x1, 1 ); + BOOST_TEST_EQ( x2, 2 ); + + BOOST_TEST_EQ( r1, r2 ); + BOOST_TEST_EQ( &*r1, &*r2 ); + } + + { + int x1 = 1; + + result r1( x1 ); + result r2( ENOENT, generic_category() ); + + r2 = r1; + + BOOST_TEST_EQ( x1, 1 ); + + BOOST_TEST_EQ( r1, r2 ); + BOOST_TEST_EQ( &*r1, &*r2 ); + } + + { + int x1 = 1; + int x2 = 2; + + result const r1( x1 ); + result r2( x2 ); + + r2 = r1; + + BOOST_TEST_EQ( x1, 1 ); + BOOST_TEST_EQ( x2, 2 ); + + BOOST_TEST_EQ( r1, r2 ); + BOOST_TEST_EQ( &*r1, &*r2 ); + } + + { + int const x1 = 1; + int const x2 = 2; + + result const r1( x1 ); + result r2( x2 ); + + r2 = r1; + + BOOST_TEST_EQ( x1, 1 ); + BOOST_TEST_EQ( x2, 2 ); + + BOOST_TEST_EQ( r1, r2 ); + BOOST_TEST_EQ( &*r1, &*r2 ); + } + + { + int x1 = 1; + + result const r1( x1 ); + result r2( ENOENT, generic_category() ); + + r2 = r1; + + BOOST_TEST_EQ( x1, 1 ); + + BOOST_TEST_EQ( r1, r2 ); + BOOST_TEST_EQ( &*r1, &*r2 ); + } + + { + int x2 = 2; + + auto ec = make_error_code( errc::invalid_argument ); + + result r1( ec ); + result r2( x2 ); + + r2 = r1; + + BOOST_TEST_EQ( x2, 2 ); + + BOOST_TEST_EQ( r1, r2 ); + } + + { + auto ec = make_error_code( errc::invalid_argument ); + + result r1( ec ); + result r2( ENOENT, generic_category() ); + + r2 = r1; + + BOOST_TEST_EQ( r1, r2 ); + } + + { + int x2 = 2; + + auto ec = make_error_code( errc::invalid_argument ); + + result const r1( ec ); + result r2( x2 ); + + r2 = r1; + + BOOST_TEST_EQ( x2, 2 ); + + BOOST_TEST_EQ( r1, r2 ); + } + + { + auto ec = make_error_code( errc::invalid_argument ); + + result const r1( ec ); + result r2( ENOENT, generic_category() ); + + r2 = r1; + + BOOST_TEST_EQ( r1, r2 ); + } + return boost::report_errors(); } diff --git a/test/result_copy_construct.cpp b/test/result_copy_construct.cpp index 859a69d..51768e9 100644 --- a/test/result_copy_construct.cpp +++ b/test/result_copy_construct.cpp @@ -145,6 +145,8 @@ int main() BOOST_TEST_EQ( X::instances, 0 ); + // + { result r; result r2( r ); @@ -177,5 +179,121 @@ int main() BOOST_TEST_EQ( r, r2 ); } + // + + { + int x1 = 1; + + result r1( x1 ); + result r2( r1 ); + + BOOST_TEST_EQ( r1, r2 ); + BOOST_TEST_EQ( &*r2, &x1 ); + } + + { + int x1 = 1; + + result const r1( x1 ); + result r2( r1 ); + + BOOST_TEST_EQ( r1, r2 ); + BOOST_TEST_EQ( &*r2, &x1 ); + } + + { + int const x1 = 1; + + result r1( x1 ); + result r2( r1 ); + + BOOST_TEST_EQ( r1, r2 ); + BOOST_TEST_EQ( &*r2, &x1 ); + } + + { + int const x1 = 1; + + result const r1( x1 ); + result r2( r1 ); + + BOOST_TEST_EQ( r1, r2 ); + BOOST_TEST_EQ( &*r2, &x1 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + X x1( 1 ); + + result r1( x1 ); + result r2( r1 ); + + BOOST_TEST_EQ( r1, r2 ); + BOOST_TEST_EQ( &*r2, &x1 ); + BOOST_TEST_EQ( X::instances, 1 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + X x1( 1 ); + + result const r1( x1 ); + result r2( r1 ); + + BOOST_TEST_EQ( r1, r2 ); + BOOST_TEST_EQ( &*r2, &x1 ); + BOOST_TEST_EQ( X::instances, 1 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + X const x1( 1 ); + + result r1( x1 ); + result r2( r1 ); + + BOOST_TEST_EQ( r1, r2 ); + BOOST_TEST_EQ( &*r2, &x1 ); + BOOST_TEST_EQ( X::instances, 1 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + X const x1( 1 ); + + result const r1( x1 ); + result r2( r1 ); + + BOOST_TEST_EQ( r1, r2 ); + BOOST_TEST_EQ( &*r2, &x1 ); + BOOST_TEST_EQ( X::instances, 1 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + auto ec = make_error_code( errc::invalid_argument ); + + result r1( ec ); + result r2( r1 ); + + BOOST_TEST_EQ( r1, r2 ); + } + + { + auto ec = make_error_code( errc::invalid_argument ); + + result const r1( ec ); + result r2( r1 ); + + BOOST_TEST_EQ( r1, r2 ); + } + + // + return boost::report_errors(); } diff --git a/test/result_default_construct.cpp b/test/result_default_construct.cpp index fe8e522..a467e36 100644 --- a/test/result_default_construct.cpp +++ b/test/result_default_construct.cpp @@ -52,6 +52,9 @@ int main() BOOST_TEST_TRAIT_FALSE((std::is_default_constructible>)); BOOST_TEST_TRAIT_FALSE((std::is_default_constructible>)); + + BOOST_TEST_TRAIT_FALSE((std::is_default_constructible>)); + BOOST_TEST_TRAIT_FALSE((std::is_default_constructible>)); } return boost::report_errors(); diff --git a/test/result_emplace.cpp b/test/result_emplace.cpp index 53a0e31..784d924 100644 --- a/test/result_emplace.cpp +++ b/test/result_emplace.cpp @@ -172,5 +172,47 @@ int main() BOOST_TEST_EQ( Y::instances, 0 ); } + { + int x1 = 1; + result r( x1 ); + + BOOST_TEST( r.has_value() ); + BOOST_TEST_EQ( r.value(), 1 ); + + int x2 = 2; + r.emplace( x2 ); + + BOOST_TEST( r.has_value() ); + BOOST_TEST_EQ( r.value(), 2 ); + } + + { + result r( ENOENT, generic_category() ); + + BOOST_TEST( !r.has_value() ); + + int x2 = 2; + r.emplace( x2 ); + + BOOST_TEST( r.has_value() ); + BOOST_TEST_EQ( r.value(), 2 ); + } + + BOOST_TEST_EQ( Y::instances, 0 ); + + { + result r( in_place_error ); + + BOOST_TEST( !r.has_value() ); + BOOST_TEST_EQ( Y::instances, 1 ); + + int x2 = 2; + r.emplace( x2 ); + + BOOST_TEST( r.has_value() ); + BOOST_TEST_EQ( *r, 2 ); + BOOST_TEST_EQ( Y::instances, 0 ); + } + return boost::report_errors(); } diff --git a/test/result_eq.cpp b/test/result_eq.cpp index 0c13e56..437131e 100644 --- a/test/result_eq.cpp +++ b/test/result_eq.cpp @@ -149,5 +149,83 @@ int main() BOOST_TEST_NE( r1, r2 ); } + { + int x1 = 1; + int x2 = 2; + + result r1( x1 ); + result r2( x2 ); + + BOOST_TEST_EQ( r1, r1 ); + BOOST_TEST_NE( r1, r2 ); + } + + { + int x1 = 1; + int x2 = 1; + + result r1( x1 ); + result r2( x2 ); + + BOOST_TEST_EQ( r1, r2 ); + } + + { + result r1( 1, generic_category() ); + result r2( 2, generic_category() ); + + BOOST_TEST_EQ( r1, r1 ); + BOOST_TEST_NE( r1, r2 ); + } + + { + int x1 = 1; + + result r1( x1 ); + result r2( 2, generic_category() ); + + BOOST_TEST_EQ( r1, r1 ); + BOOST_TEST_NE( r1, r2 ); + } + + { + X x1( 1 ); + X x2( 2 ); + + result r1( x1 ); + result r2( x2 ); + + BOOST_TEST_EQ( r1, r1 ); + BOOST_TEST_NE( r1, r2 ); + } + + { + X x1( 1 ); + X x2( 1 ); + + result r1( x1 ); + result r2( x2 ); + + BOOST_TEST_EQ( r1, r2 ); + } + + { + result r1( in_place_error, 1 ); + result r2( in_place_error, 2 ); + + BOOST_TEST_EQ( r1, r1 ); + BOOST_TEST_NE( r1, r2 ); + } + + { + X x1( 1 ); + + result r1( x1 ); + result r2( in_place_error, 2 ); + + BOOST_TEST_EQ( r1, r1 ); + BOOST_TEST_NE( r1, r2 ); + } + return boost::report_errors(); } diff --git a/test/result_errc_construct.cpp b/test/result_errc_construct.cpp index 6d45368..357fd52 100644 --- a/test/result_errc_construct.cpp +++ b/test/result_errc_construct.cpp @@ -19,5 +19,14 @@ int main() BOOST_TEST_TRAIT_FALSE((std::is_convertible>)); BOOST_TEST_TRAIT_FALSE((std::is_constructible, errc::errc_t>)); + BOOST_TEST_TRAIT_FALSE((std::is_convertible>)); + BOOST_TEST_TRAIT_FALSE((std::is_constructible, errc::errc_t>)); + + BOOST_TEST_TRAIT_FALSE((std::is_convertible>)); + BOOST_TEST_TRAIT_FALSE((std::is_constructible, errc::errc_t>)); + + BOOST_TEST_TRAIT_FALSE((std::is_convertible>)); + BOOST_TEST_TRAIT_FALSE((std::is_constructible, errc::errc_t>)); + return boost::report_errors(); } diff --git a/test/result_error_access.cpp b/test/result_error_access.cpp index 66bbbe3..eba50cc 100644 --- a/test/result_error_access.cpp +++ b/test/result_error_access.cpp @@ -152,6 +152,8 @@ int main() BOOST_TEST_EQ( (result( "s" ).error().v_), 0 ); } + // + { result r; @@ -208,5 +210,71 @@ int main() BOOST_TEST_EQ( result( ec ).error(), ec ); } + // + + { + int x1 = 1; + + result r( x1 ); + + BOOST_TEST( r.has_value() ); + BOOST_TEST( !r.has_error() ); + + BOOST_TEST_EQ( r.error(), error_code() ); + } + + { + int x1 = 1; + + result const r( x1 ); + + BOOST_TEST( r.has_value() ); + BOOST_TEST( !r.has_error() ); + + BOOST_TEST_EQ( r.error(), error_code() ); + } + + { + int x1 = 1; + + BOOST_TEST( result( x1 ).has_value() ); + BOOST_TEST( !result( x1 ).has_error() ); + + BOOST_TEST_EQ( result( x1 ).error(), error_code() ); + } + + { + auto ec = make_error_code( errc::invalid_argument ); + + result r( ec ); + + BOOST_TEST( !r.has_value() ); + BOOST_TEST( r.has_error() ); + + BOOST_TEST_EQ( r.error(), ec ); + } + + { + auto ec = make_error_code( errc::invalid_argument ); + + result const r( ec ); + + BOOST_TEST( !r.has_value() ); + BOOST_TEST( r.has_error() ); + + BOOST_TEST_EQ( r.error(), ec ); + } + + { + auto ec = make_error_code( errc::invalid_argument ); + + BOOST_TEST( !result( ec ).has_value() ); + BOOST_TEST( result( ec ).has_error() ); + + BOOST_TEST_EQ( result( ec ).error(), ec ); + } + + // + return boost::report_errors(); } diff --git a/test/result_error_construct3.cpp b/test/result_error_construct3.cpp index 162ca5b..cc85470 100644 --- a/test/result_error_construct3.cpp +++ b/test/result_error_construct3.cpp @@ -157,5 +157,27 @@ int main() BOOST_TEST_EQ( r.error(), error_code( EINVAL, generic_category() ) ); } + { + auto ec = make_error_code( errc::invalid_argument ); + + using R = result; + R r( R::in_place_error, ec ); + + BOOST_TEST( !r.has_value() ); + BOOST_TEST( r.has_error() ); + + BOOST_TEST_EQ( r.error(), ec ); + } + + { + using R = result; + R r( R::in_place_error, EINVAL, generic_category() ); + + BOOST_TEST( !r.has_value() ); + BOOST_TEST( r.has_error() ); + + BOOST_TEST_EQ( r.error(), error_code( EINVAL, generic_category() ) ); + } + return boost::report_errors(); } diff --git a/test/result_error_construct5.cpp b/test/result_error_construct5.cpp new file mode 100644 index 0000000..451d85f --- /dev/null +++ b/test/result_error_construct5.cpp @@ -0,0 +1,160 @@ +// Copyright 2017, 2021 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include +#include +#include + +using namespace boost::system; + +struct X +{ + static int instances; + + int v_; + + X(): v_() { ++instances; } + + explicit X( int v ): v_( v ) { ++instances; } + + X( int v1, int v2 ): v_( v1+v2 ) { ++instances; } + X( int v1, int v2, int v3 ): v_( v1+v2+v3 ) { ++instances; } + + X( X const& r ): v_( r.v_ ) { ++instances; } + + X& operator=( X const& ) = delete; + + ~X() { --instances; } +}; + +int X::instances = 0; + +int main() +{ + { + auto ec = make_error_code( errc::invalid_argument ); + + result r( ec ); + + BOOST_TEST( !r.has_value() ); + BOOST_TEST( r.has_error() ); + + BOOST_TEST_EQ( r.error(), ec ); + } + + { + auto ec = make_error_code( errc::invalid_argument ); + + result r = ec; + + BOOST_TEST( !r.has_value() ); + BOOST_TEST( r.has_error() ); + + BOOST_TEST_EQ( r.error(), ec ); + } + + { + result r( EINVAL, generic_category() ); + + BOOST_TEST( !r.has_value() ); + BOOST_TEST( r.has_error() ); + + BOOST_TEST_EQ( r.error(), error_code( EINVAL, generic_category() ) ); + } + + { + auto ec = make_error_code( errc::invalid_argument ); + + result r( in_place_error, ec ); + + BOOST_TEST( !r.has_value() ); + BOOST_TEST( r.has_error() ); + + BOOST_TEST_EQ( r.error(), ec ); + } + + { + result r( in_place_error, EINVAL, generic_category() ); + + BOOST_TEST( !r.has_value() ); + BOOST_TEST( r.has_error() ); + + BOOST_TEST_EQ( r.error(), error_code( EINVAL, generic_category() ) ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + result r( 1 ); + + BOOST_TEST( !r.has_value() ); + BOOST_TEST( r.has_error() ); + + BOOST_TEST_EQ( r.error().v_, 1 ); + + BOOST_TEST_EQ( X::instances, 1 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + result r( 1, 2 ); + + BOOST_TEST( !r.has_value() ); + BOOST_TEST( r.has_error() ); + + BOOST_TEST_EQ( r.error().v_, 1+2 ); + + BOOST_TEST_EQ( X::instances, 1 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + result r( 1, 2, 3 ); + + BOOST_TEST( !r.has_value() ); + BOOST_TEST( r.has_error() ); + + BOOST_TEST_EQ( r.error().v_, 1+2+3 ); + + BOOST_TEST_EQ( X::instances, 1 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + result r( in_place_error, 1 ); + + BOOST_TEST( !r.has_value() ); + BOOST_TEST( r.has_error() ); + + BOOST_TEST_EQ( r.error().v_, 1 ); + + BOOST_TEST_EQ( X::instances, 1 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + BOOST_TEST_TRAIT_TRUE((std::is_constructible, error_code>)); + BOOST_TEST_TRAIT_TRUE((std::is_convertible>)); + + BOOST_TEST_TRAIT_TRUE((std::is_constructible, int>)); + BOOST_TEST_TRAIT_FALSE((std::is_convertible>)); + + BOOST_TEST_TRAIT_TRUE((std::is_constructible, int>)); + BOOST_TEST_TRAIT_FALSE((std::is_convertible>)); + + // There's an ambiguity here between int& and X, but since is_convertible + // is true, is_constructible can't be false. + + // BOOST_TEST_TRAIT_FALSE((std::is_constructible, int&>)); + BOOST_TEST_TRAIT_TRUE((std::is_convertible>)); + } + + return boost::report_errors(); +} diff --git a/test/result_error_move.cpp b/test/result_error_move.cpp index 9aea7f2..471393c 100644 --- a/test/result_error_move.cpp +++ b/test/result_error_move.cpp @@ -55,7 +55,9 @@ int main() BOOST_TEST_EQ( (result( "s" ).error().v_), 0 ); } - { + // + + { result r( 1 ); BOOST_TEST( !r.has_value() ); @@ -87,5 +89,45 @@ int main() BOOST_TEST_EQ( (result().error().v_), 0 ); } + // + + { + result r( 1 ); + + BOOST_TEST( !r.has_value() ); + BOOST_TEST( r.has_error() ); + + BOOST_TEST_EQ( std::move( r ).error().v_, 1 ); + } + + { + BOOST_TEST(( !result( 1 ).has_value() )); + BOOST_TEST(( result( 1 ).has_error() )); + + BOOST_TEST_EQ( (result( 1 ).error().v_), 1 ); + } + + { + double x = 1.0; + + result r( x ); + + BOOST_TEST( r.has_value() ); + BOOST_TEST( !r.has_error() ); + + BOOST_TEST_EQ( std::move( r ).error().v_, 0 ); + } + + { + double x = 1.0; + + BOOST_TEST(( result( x ).has_value() )); + BOOST_TEST(( !result( x ).has_error() )); + + BOOST_TEST_EQ( (result( x ).error().v_), 0 ); + } + + // + return boost::report_errors(); } diff --git a/test/result_move_assign.cpp b/test/result_move_assign.cpp index 1266b74..cb425d9 100644 --- a/test/result_move_assign.cpp +++ b/test/result_move_assign.cpp @@ -508,6 +508,8 @@ int main() BOOST_TEST_EQ( Y::instances, 0 ); + // + { result r; result r2; @@ -600,5 +602,110 @@ int main() BOOST_TEST_EQ( r2.error(), ec ); } + // + + { + int x1 = 1; + int x2 = 2; + + result r1( x1 ); + result r2( x2 ); + + r2 = std::move( r1 ); + + BOOST_TEST_EQ( x1, 1 ); + BOOST_TEST_EQ( x2, 2 ); + + BOOST_TEST( r2.has_value() ); + BOOST_TEST( !r2.has_error() ); + + BOOST_TEST_EQ( r2.value(), 1 ); + + BOOST_TEST_EQ( r1, r2 ); + BOOST_TEST_EQ( &*r1, &*r2 ); + } + + { + int x1 = 1; + + result r1( x1 ); + result r2( ENOENT, generic_category() ); + + r2 = std::move( r1 ); + + BOOST_TEST_EQ( x1, 1 ); + + BOOST_TEST( r2.has_value() ); + BOOST_TEST( !r2.has_error() ); + + BOOST_TEST_EQ( r2.value(), 1 ); + + BOOST_TEST_EQ( r1, r2 ); + } + + { + int x1 = 1; + + auto ec = make_error_code( errc::invalid_argument ); + + result r1( ec ); + result r2( x1 ); + + r2 = std::move( r1 ); + + BOOST_TEST_EQ( x1, 1 ); + + BOOST_TEST( !r2.has_value() ); + BOOST_TEST( r2.has_error() ); + + BOOST_TEST_EQ( r2.error(), ec ); + } + + { + int x1 = 1; + + auto ec = make_error_code( errc::invalid_argument ); + + result r2( x1 ); + + r2 = result( ec ); + + BOOST_TEST_EQ( x1, 1 ); + + BOOST_TEST( !r2.has_value() ); + BOOST_TEST( r2.has_error() ); + + BOOST_TEST_EQ( r2.error(), ec ); + } + + { + auto ec = make_error_code( errc::invalid_argument ); + + result r1( ec ); + result r2( ENOENT, generic_category() ); + + r2 = std::move( r1 ); + + BOOST_TEST( !r2.has_value() ); + BOOST_TEST( r2.has_error() ); + + BOOST_TEST_EQ( r2.error(), ec ); + } + + { + auto ec = make_error_code( errc::invalid_argument ); + + result r2( ENOENT, generic_category() ); + + r2 = result( ec ); + + BOOST_TEST( !r2.has_value() ); + BOOST_TEST( r2.has_error() ); + + BOOST_TEST_EQ( r2.error(), ec ); + } + + // + return boost::report_errors(); } diff --git a/test/result_move_construct.cpp b/test/result_move_construct.cpp index 54e04cb..38d93b4 100644 --- a/test/result_move_construct.cpp +++ b/test/result_move_construct.cpp @@ -207,6 +207,8 @@ int main() BOOST_TEST_EQ( X::instances, 0 ); + // + { result r; result r2( std::move( r ) ); @@ -245,5 +247,149 @@ int main() BOOST_TEST_EQ( r2.error(), ec ); } + // + + { + int x1 = 1; + + result r1( x1 ); + result r2( std::move( r1 ) ); + + BOOST_TEST( r1.has_value() ); + BOOST_TEST( !r1.has_error() ); + + BOOST_TEST_EQ( r1.value(), 1 ); + BOOST_TEST_EQ( &*r1, &x1 ); + + BOOST_TEST( r2.has_value() ); + BOOST_TEST( !r2.has_error() ); + + BOOST_TEST_EQ( r2.value(), 1 ); + BOOST_TEST_EQ( &*r2, &x1 ); + } + + { + int const x1 = 1; + + result r1( x1 ); + result r2( std::move( r1 ) ); + + BOOST_TEST( r1.has_value() ); + BOOST_TEST( !r1.has_error() ); + + BOOST_TEST_EQ( r1.value(), 1 ); + BOOST_TEST_EQ( &*r1, &x1 ); + + BOOST_TEST( r2.has_value() ); + BOOST_TEST( !r2.has_error() ); + + BOOST_TEST_EQ( r2.value(), 1 ); + BOOST_TEST_EQ( &*r2, &x1 ); + } + + { + int x1 = 1; + + result r2(( result( x1 ) )); + + BOOST_TEST( r2.has_value() ); + BOOST_TEST( !r2.has_error() ); + + BOOST_TEST_EQ( r2.value(), 1 ); + BOOST_TEST_EQ( &*r2, &x1 ); + } + + { + int const x1 = 1; + + result r2(( result( x1 ) )); + + BOOST_TEST( r2.has_value() ); + BOOST_TEST( !r2.has_error() ); + + BOOST_TEST_EQ( r2.value(), 1 ); + BOOST_TEST_EQ( &*r2, &x1 ); + } + + { + X x1( 1 ); + + result r1( x1 ); + result r2( std::move( r1 ) ); + + BOOST_TEST( r1.has_value() ); + BOOST_TEST( !r1.has_error() ); + + BOOST_TEST_EQ( r1.value().v_, 1 ); + BOOST_TEST_EQ( &*r1, &x1 ); + + BOOST_TEST( r2.has_value() ); + BOOST_TEST( !r2.has_error() ); + + BOOST_TEST_EQ( r2.value().v_, 1 ); + BOOST_TEST_EQ( &*r2, &x1 ); + + BOOST_TEST_EQ( X::instances, 1 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + X x1( 1 ); + + result r2(( result( x1 ) )); + + BOOST_TEST( r2.has_value() ); + BOOST_TEST( !r2.has_error() ); + + BOOST_TEST_EQ( r2.value().v_, 1 ); + BOOST_TEST_EQ( &*r2, &x1 ); + + BOOST_TEST_EQ( X::instances, 1 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + X const x1( 1 ); + + result r1( x1 ); + result r2( std::move( r1 ) ); + + BOOST_TEST( r1.has_value() ); + BOOST_TEST( !r1.has_error() ); + + BOOST_TEST_EQ( r1.value().v_, 1 ); + BOOST_TEST_EQ( &*r1, &x1 ); + + BOOST_TEST( r2.has_value() ); + BOOST_TEST( !r2.has_error() ); + + BOOST_TEST_EQ( r2.value().v_, 1 ); + BOOST_TEST_EQ( &*r2, &x1 ); + + BOOST_TEST_EQ( X::instances, 1 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + X const x1( 1 ); + + result r2(( result( x1 ) )); + + BOOST_TEST( r2.has_value() ); + BOOST_TEST( !r2.has_error() ); + + BOOST_TEST_EQ( r2.value().v_, 1 ); + BOOST_TEST_EQ( &*r2, &x1 ); + + BOOST_TEST_EQ( X::instances, 1 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + // + return boost::report_errors(); } diff --git a/test/result_swap.cpp b/test/result_swap.cpp index b332536..d8def29 100644 --- a/test/result_swap.cpp +++ b/test/result_swap.cpp @@ -259,5 +259,55 @@ int main() BOOST_TEST_EQ( r2, r2c ); } + { + int x1 = 1; + int x2 = 2; + + result r1( x1 ), r1c( r1 ); + result r2( x2 ), r2c( r2 ); + + r1.swap( r2 ); + + BOOST_TEST_EQ( r1, r2c ); + BOOST_TEST_EQ( r2, r1c ); + + swap( r1, r2 ); + + BOOST_TEST_EQ( r1, r1c ); + BOOST_TEST_EQ( r2, r2c ); + } + + { + result r1( 1, generic_category() ), r1c( r1 ); + result r2( 2, generic_category() ), r2c( r2 ); + + r1.swap( r2 ); + + BOOST_TEST_EQ( r1, r2c ); + BOOST_TEST_EQ( r2, r1c ); + + swap( r1, r2 ); + + BOOST_TEST_EQ( r1, r1c ); + BOOST_TEST_EQ( r2, r2c ); + } + + { + int x1 = 1; + + result r1( x1 ), r1c( r1 ); + result r2( 2, generic_category() ), r2c( r2 ); + + r1.swap( r2 ); + + BOOST_TEST_EQ( r1, r2c ); + BOOST_TEST_EQ( r2, r1c ); + + swap( r1, r2 ); + + BOOST_TEST_EQ( r1, r1c ); + BOOST_TEST_EQ( r2, r2c ); + } + return boost::report_errors(); } diff --git a/test/result_typedefs.cpp b/test/result_typedefs.cpp index 6a9a63d..72d36ff 100644 --- a/test/result_typedefs.cpp +++ b/test/result_typedefs.cpp @@ -12,11 +12,28 @@ struct X {}; int main() { BOOST_TEST_TRAIT_SAME( result::value_type, int ); - BOOST_TEST_TRAIT_SAME( result::value_type, X ); - BOOST_TEST_TRAIT_SAME( result::value_type, void ); - BOOST_TEST_TRAIT_SAME( result::error_type, error_code ); + + BOOST_TEST_TRAIT_SAME( result::value_type, X ); + BOOST_TEST_TRAIT_SAME( result::error_type, error_code ); + + BOOST_TEST_TRAIT_SAME( result::value_type, void ); + BOOST_TEST_TRAIT_SAME( result::error_type, error_code ); + + BOOST_TEST_TRAIT_SAME( result::value_type, int& ); + BOOST_TEST_TRAIT_SAME( result::error_type, error_code ); + + BOOST_TEST_TRAIT_SAME( result::value_type, int ); BOOST_TEST_TRAIT_SAME( result::error_type, X ); + BOOST_TEST_TRAIT_SAME( result::value_type, X ); + BOOST_TEST_TRAIT_SAME( result::error_type, X ); + + BOOST_TEST_TRAIT_SAME( result::value_type, void ); + BOOST_TEST_TRAIT_SAME( result::error_type, X ); + + BOOST_TEST_TRAIT_SAME( result::value_type, int& ); + BOOST_TEST_TRAIT_SAME( result::error_type, X ); + return boost::report_errors(); } diff --git a/test/result_value_access.cpp b/test/result_value_access.cpp index 96a392c..8da97b4 100644 --- a/test/result_value_access.cpp +++ b/test/result_value_access.cpp @@ -336,6 +336,8 @@ int main() BOOST_TEST_EQ( (result( ec ).operator->()), static_cast(0) ); } + // + { result r; @@ -497,5 +499,179 @@ int main() BOOST_TEST_EQ( r.operator->(), static_cast(0) ); } + // + + { + int x1 = 1; + + result r( x1 ); + + BOOST_TEST( r.has_value() ); + BOOST_TEST( !r.has_error() ); + + BOOST_TEST( r ); + BOOST_TEST_NOT( !r ); + + BOOST_TEST_EQ( r.value(), 1 ); + BOOST_TEST_EQ( *r, 1 ); + + BOOST_TEST_EQ( r.operator->(), &*r ); + } + + { + int x1 = 1; + + result const r( x1 ); + + BOOST_TEST( r.has_value() ); + BOOST_TEST( !r.has_error() ); + + BOOST_TEST( r ); + BOOST_TEST_NOT( !r ); + + BOOST_TEST_EQ( r.value(), 1 ); + BOOST_TEST_EQ( *r, 1 ); + + BOOST_TEST_EQ( r.operator->(), &*r ); + } + + { + int x1 = 1; + + BOOST_TEST( result( x1 ).has_value() ); + BOOST_TEST( !result( x1 ).has_error() ); + + BOOST_TEST( result( x1 ) ); + BOOST_TEST_NOT( !result( x1 ) ); + + BOOST_TEST_EQ( result( x1 ).value(), 1 ); + BOOST_TEST_EQ( *result( x1 ), 1 ); + + BOOST_TEST_EQ( result( x1 ).operator->(), &x1 ); + } + + { + auto ec = make_error_code( errc::invalid_argument ); + + result r( ec ); + + BOOST_TEST( !r.has_value() ); + BOOST_TEST( r.has_error() ); + + BOOST_TEST_NOT( r ); + BOOST_TEST( !r ); + + BOOST_TEST_THROWS( r.value(), system_error ); + + BOOST_TEST_EQ( r.operator->(), static_cast(0) ); + } + + { + auto ec = make_error_code( errc::invalid_argument ); + + result const r( ec ); + + BOOST_TEST( !r.has_value() ); + BOOST_TEST( r.has_error() ); + + BOOST_TEST_NOT( r ); + BOOST_TEST( !r ); + + BOOST_TEST_THROWS( r.value(), system_error ); + + BOOST_TEST_EQ( r.operator->(), static_cast(0) ); + } + + { + auto ec = make_error_code( errc::invalid_argument ); + + BOOST_TEST( !result( ec ).has_value() ); + BOOST_TEST( result( ec ).has_error() ); + + BOOST_TEST_NOT( result( ec ) ); + BOOST_TEST( !result( ec ) ); + + BOOST_TEST_THROWS( result( ec ).value(), system_error ); + + BOOST_TEST_EQ( result( ec ).operator->(), static_cast(0) ); + } + + { + auto ec = make_error_code( std::errc::invalid_argument ); + + result const r( ec ); + + BOOST_TEST( !r.has_value() ); + BOOST_TEST( r.has_error() ); + + BOOST_TEST_NOT( r ); + BOOST_TEST( !r ); + + BOOST_TEST_THROWS( r.value(), std::system_error ); + + BOOST_TEST_EQ( r.operator->(), static_cast(0) ); + } + + { + result const r( in_place_error, errc::invalid_argument ); + + BOOST_TEST( !r.has_value() ); + BOOST_TEST( r.has_error() ); + + BOOST_TEST_NOT( r ); + BOOST_TEST( !r ); + + BOOST_TEST_THROWS( r.value(), system_error ); + + BOOST_TEST_EQ( r.operator->(), static_cast(0) ); + } + + { + result const r( std::errc::invalid_argument ); + + BOOST_TEST( !r.has_value() ); + BOOST_TEST( r.has_error() ); + + BOOST_TEST_NOT( r ); + BOOST_TEST( !r ); + + BOOST_TEST_THROWS( r.value(), std::system_error ); + + BOOST_TEST_EQ( r.operator->(), static_cast(0) ); + } + + { + result const r( std::make_exception_ptr( E2() ) ); + + BOOST_TEST( !r.has_value() ); + BOOST_TEST( r.has_error() ); + + BOOST_TEST_NOT( r ); + BOOST_TEST( !r ); + +#if defined(BOOST_CLANG_VERSION) && BOOST_CLANG_VERSION < 30600 +#else + BOOST_TEST_THROWS( r.value(), E2 ); +#endif + + BOOST_TEST_EQ( r.operator->(), static_cast(0) ); + } + + { + result const r( in_place_error ); + + BOOST_TEST( !r.has_value() ); + BOOST_TEST( r.has_error() ); + + BOOST_TEST_NOT( r ); + BOOST_TEST( !r ); + + BOOST_TEST_THROWS( r.value(), std::bad_exception ); + + BOOST_TEST_EQ( r.operator->(), static_cast(0) ); + } + + // + return boost::report_errors(); } diff --git a/test/result_value_construct3.cpp b/test/result_value_construct3.cpp index 040a592..ebcca2a 100644 --- a/test/result_value_construct3.cpp +++ b/test/result_value_construct3.cpp @@ -114,5 +114,29 @@ int main() BOOST_TEST( !r.has_error() ); } + { + int x1 = 1; + + using R = result; + R r( R::in_place_value, x1 ); + + BOOST_TEST( r.has_value() ); + BOOST_TEST( !r.has_error() ); + + BOOST_TEST_EQ( r.value(), 1 ); + } + + { + int x1 = 1; + + using R = result; + R r( R::in_place_value, x1 ); + + BOOST_TEST( r.has_value() ); + BOOST_TEST( !r.has_error() ); + + BOOST_TEST_EQ( *r, 1 ); + } + return boost::report_errors(); } diff --git a/test/result_value_construct6.cpp b/test/result_value_construct6.cpp new file mode 100644 index 0000000..f9dd3fc --- /dev/null +++ b/test/result_value_construct6.cpp @@ -0,0 +1,121 @@ +// Copyright 2017, 2021, 2023 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include + +using namespace boost::system; + +struct X +{ + static int instances; + + int v_; + + explicit X( int v ): v_( v ) { ++instances; } + + X( X const& ) = delete; + X& operator=( X const& ) = delete; + + ~X() { --instances; } +}; + +int X::instances = 0; + +int main() +{ + { + int x = 0; + result r( x ); + + BOOST_TEST( r.has_value() ); + BOOST_TEST( !r.has_error() ); + + BOOST_TEST_EQ( r.value(), 0 ); + } + + { + int x = 0; + result r = x; + + BOOST_TEST( r.has_value() ); + BOOST_TEST( !r.has_error() ); + + BOOST_TEST_EQ( r.value(), 0 ); + } + + { + int x = 1; + result r( in_place_value, x ); + + BOOST_TEST( r.has_value() ); + BOOST_TEST( !r.has_error() ); + + BOOST_TEST_EQ( *r, 1 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + X x( 1 ); + result r( x ); + + BOOST_TEST( r.has_value() ); + BOOST_TEST( !r.has_error() ); + + BOOST_TEST_EQ( r.value().v_, 1 ); + + BOOST_TEST_EQ( X::instances, 1 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + X x( 1 ); + result r = x; + + BOOST_TEST( r.has_value() ); + BOOST_TEST( !r.has_error() ); + + BOOST_TEST_EQ( r.value().v_, 1 ); + + BOOST_TEST_EQ( X::instances, 1 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + X x( 1 ); + result r( in_place_value, x ); + + BOOST_TEST( r.has_value() ); + BOOST_TEST( !r.has_error() ); + + BOOST_TEST_EQ( r->v_, 1 ); + + BOOST_TEST_EQ( X::instances, 1 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + BOOST_TEST_TRAIT_TRUE((std::is_constructible, int&>)); + BOOST_TEST_TRAIT_TRUE((std::is_convertible>)); + + BOOST_TEST_TRAIT_FALSE((std::is_constructible, int const&>)); + BOOST_TEST_TRAIT_FALSE((std::is_convertible>)); + + BOOST_TEST_TRAIT_FALSE((std::is_constructible, int>)); + BOOST_TEST_TRAIT_FALSE((std::is_convertible>)); + + BOOST_TEST_TRAIT_FALSE((std::is_constructible, int&>)); + BOOST_TEST_TRAIT_FALSE((std::is_constructible, int&>)); + + BOOST_TEST_TRAIT_FALSE((std::is_constructible, int>)); + BOOST_TEST_TRAIT_FALSE((std::is_convertible>)); + } + + return boost::report_errors(); +} diff --git a/test/result_value_construct7.cpp b/test/result_value_construct7.cpp new file mode 100644 index 0000000..97e5343 --- /dev/null +++ b/test/result_value_construct7.cpp @@ -0,0 +1,211 @@ +// Copyright 2017, 2021, 2023 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include + +using namespace boost::system; + +struct X +{ + static int instances; + + int v_; + + explicit X( int v ): v_( v ) { ++instances; } + + X( X const& ) = delete; + X& operator=( X const& ) = delete; + + ~X() { --instances; } +}; + +int X::instances = 0; + +int main() +{ + { + int x = 0; + result r( x ); + + BOOST_TEST( r.has_value() ); + BOOST_TEST( !r.has_error() ); + + BOOST_TEST_EQ( r.value(), 0 ); + } + + { + int const x = 0; + result r( x ); + + BOOST_TEST( r.has_value() ); + BOOST_TEST( !r.has_error() ); + + BOOST_TEST_EQ( r.value(), 0 ); + } + + { + int x = 0; + result r = x; + + BOOST_TEST( r.has_value() ); + BOOST_TEST( !r.has_error() ); + + BOOST_TEST_EQ( r.value(), 0 ); + } + + { + int const x = 0; + result r = x; + + BOOST_TEST( r.has_value() ); + BOOST_TEST( !r.has_error() ); + + BOOST_TEST_EQ( r.value(), 0 ); + } + + { + int x = 1; + result r( in_place_value, x ); + + BOOST_TEST( r.has_value() ); + BOOST_TEST( !r.has_error() ); + + BOOST_TEST_EQ( *r, 1 ); + } + + { + int const x = 1; + result r( in_place_value, x ); + + BOOST_TEST( r.has_value() ); + BOOST_TEST( !r.has_error() ); + + BOOST_TEST_EQ( *r, 1 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + X x( 1 ); + result r( x ); + + BOOST_TEST( r.has_value() ); + BOOST_TEST( !r.has_error() ); + + BOOST_TEST_EQ( r.value().v_, 1 ); + + BOOST_TEST_EQ( X::instances, 1 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + X const x( 1 ); + result r( x ); + + BOOST_TEST( r.has_value() ); + BOOST_TEST( !r.has_error() ); + + BOOST_TEST_EQ( r.value().v_, 1 ); + + BOOST_TEST_EQ( X::instances, 1 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + X x( 1 ); + result r = x; + + BOOST_TEST( r.has_value() ); + BOOST_TEST( !r.has_error() ); + + BOOST_TEST_EQ( r.value().v_, 1 ); + + BOOST_TEST_EQ( X::instances, 1 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + X const x( 1 ); + result r = x; + + BOOST_TEST( r.has_value() ); + BOOST_TEST( !r.has_error() ); + + BOOST_TEST_EQ( r.value().v_, 1 ); + + BOOST_TEST_EQ( X::instances, 1 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + X x( 1 ); + result r( in_place_value, x ); + + BOOST_TEST( r.has_value() ); + BOOST_TEST( !r.has_error() ); + + BOOST_TEST_EQ( r->v_, 1 ); + + BOOST_TEST_EQ( X::instances, 1 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + X const x( 1 ); + result r( in_place_value, x ); + + BOOST_TEST( r.has_value() ); + BOOST_TEST( !r.has_error() ); + + BOOST_TEST_EQ( r->v_, 1 ); + + BOOST_TEST_EQ( X::instances, 1 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + BOOST_TEST_TRAIT_TRUE((std::is_constructible, int&>)); + BOOST_TEST_TRAIT_TRUE((std::is_convertible>)); + + BOOST_TEST_TRAIT_TRUE((std::is_constructible, int const&>)); + BOOST_TEST_TRAIT_TRUE((std::is_convertible>)); + + BOOST_TEST_TRAIT_FALSE((std::is_constructible, int>)); + BOOST_TEST_TRAIT_FALSE((std::is_convertible>)); + + BOOST_TEST_TRAIT_FALSE((std::is_constructible, int&>)); + BOOST_TEST_TRAIT_FALSE((std::is_convertible>)); + + BOOST_TEST_TRAIT_FALSE((std::is_constructible, int const&>)); + BOOST_TEST_TRAIT_FALSE((std::is_convertible>)); + + BOOST_TEST_TRAIT_FALSE((std::is_constructible, int>)); + BOOST_TEST_TRAIT_FALSE((std::is_convertible>)); + + BOOST_TEST_TRAIT_FALSE((std::is_constructible, int&>)); + BOOST_TEST_TRAIT_FALSE((std::is_constructible, int&>)); + + BOOST_TEST_TRAIT_FALSE((std::is_constructible, int const&>)); + BOOST_TEST_TRAIT_FALSE((std::is_constructible, int const&>)); + + BOOST_TEST_TRAIT_FALSE((std::is_constructible, int>)); + BOOST_TEST_TRAIT_FALSE((std::is_constructible, int>)); + + BOOST_TEST_TRAIT_FALSE((std::is_constructible, int>)); + BOOST_TEST_TRAIT_FALSE((std::is_convertible>)); + + BOOST_TEST_TRAIT_FALSE((std::is_constructible, X const>)); + BOOST_TEST_TRAIT_FALSE((std::is_convertible>)); + } + + return boost::report_errors(); +}