diff --git a/SG14/inplace_function.h b/SG14/inplace_function.h index f36d988b..cddd81ee 100644 --- a/SG14/inplace_function.h +++ b/SG14/inplace_function.h @@ -159,6 +159,12 @@ template< > class inplace_function; // unspecified +namespace inplace_function_detail { + template struct is_inplace_function : std::false_type {}; + template + struct is_inplace_function> : std::true_type {}; +} // namespace inplace_function_detail + template< typename R, typename... Args, @@ -184,10 +190,7 @@ class inplace_function template< typename T, typename C = std::decay_t, - typename = std::enable_if_t< - !(std::is_same::value - || std::is_convertible::value) - > + typename = std::enable_if_t::value> > inplace_function(T&& closure) { @@ -214,6 +217,26 @@ class inplace_function ::new (std::addressof(storage_)) C{std::forward(closure)}; } + template + inplace_function(const inplace_function& other) + : inplace_function(other.vtable_ptr_, other.vtable_ptr_->copy_ptr, std::addressof(other.storage_)) + { + static_assert(inplace_function_detail::is_valid_inplace_dst< + Capacity, Alignment, Cap, Align + >::value, "conversion not allowed"); + } + + template + inplace_function(inplace_function&& other) noexcept + : inplace_function(other.vtable_ptr_, other.vtable_ptr_->relocate_ptr, std::addressof(other.storage_)) + { + static_assert(inplace_function_detail::is_valid_inplace_dst< + Capacity, Alignment, Cap, Align + >::value, "conversion not allowed"); + + other.vtable_ptr_ = std::addressof(inplace_function_detail::empty_vtable); + } + inplace_function(std::nullptr_t) noexcept : vtable_ptr_{std::addressof(inplace_function_detail::empty_vtable)} {} @@ -301,28 +324,6 @@ class inplace_function return vtable_ptr_ != std::addressof(inplace_function_detail::empty_vtable); } - template - operator inplace_function() const& - { - static_assert(inplace_function_detail::is_valid_inplace_dst< - Cap, Align, Capacity, Alignment - >::value, "conversion not allowed"); - - return {vtable_ptr_, vtable_ptr_->copy_ptr, std::addressof(storage_)}; - } - - template - operator inplace_function() && noexcept - { - static_assert(inplace_function_detail::is_valid_inplace_dst< - Cap, Align, Capacity, Alignment - >::value, "conversion not allowed"); - - auto vtable_ptr = std::exchange(vtable_ptr_, std::addressof(inplace_function_detail::empty_vtable)); - - return {vtable_ptr, vtable_ptr->relocate_ptr, std::addressof(storage_)}; - } - void swap(inplace_function& other) noexcept { if (this == std::addressof(other)) return; diff --git a/SG14_test/inplace_function_test.cpp b/SG14_test/inplace_function_test.cpp index d41ddacb..95e56031 100644 --- a/SG14_test/inplace_function_test.cpp +++ b/SG14_test/inplace_function_test.cpp @@ -439,6 +439,57 @@ static void RvalueRefParameter() g(std::make_unique(42)); } +static void test_is_convertible() +{ + static_assert(std::is_convertible>::value, ""); + static_assert(std::is_convertible>::value, ""); + static_assert(std::is_convertible>::value, ""); + static_assert(std::is_convertible>::value, ""); +} + +namespace { +struct InstrumentedCopyConstructor { + static int copies; + static int moves; + InstrumentedCopyConstructor() = default; + InstrumentedCopyConstructor(const InstrumentedCopyConstructor&) { + copies += 1; + } + InstrumentedCopyConstructor(InstrumentedCopyConstructor&&) { + moves += 1; + } +}; +int InstrumentedCopyConstructor::copies = 0; +int InstrumentedCopyConstructor::moves = 0; +} // anonymous namespace + +static void test_return_by_move() +{ + using IPF20 = stdext::inplace_function; + using IPF40 = stdext::inplace_function; + static_assert(std::is_convertible::value, ""); + static_assert(std::is_convertible::value, ""); + static_assert(std::is_convertible::value, ""); + static_assert(std::is_convertible::value, ""); + static_assert(std::is_convertible::value, ""); + + auto foo = []() -> IPF40 { + InstrumentedCopyConstructor cc; + InstrumentedCopyConstructor::copies = 0; + InstrumentedCopyConstructor::moves = 0; + IPF20 f = [cc]() { }; + assert(InstrumentedCopyConstructor::copies == 1); + assert(InstrumentedCopyConstructor::moves == 1); + InstrumentedCopyConstructor::copies = 0; + InstrumentedCopyConstructor::moves = 0; + return f; + }; + IPF40 f = foo(); + assert(InstrumentedCopyConstructor::copies == 0); + assert(InstrumentedCopyConstructor::moves == 1); +} + + void sg14_test::inplace_function_test() { // first set of tests (from Optiver) @@ -523,6 +574,8 @@ void sg14_test::inplace_function_test() test_overloaded_operator_new(); test_move_construction_is_noexcept(); test_move_construction_from_smaller_buffer_is_noexcept(); + test_is_convertible(); + test_return_by_move(); } #ifdef TEST_MAIN