diff --git a/include/etl/optional.h b/include/etl/optional.h index 244aa3cb..371c9f2a 100644 --- a/include/etl/optional.h +++ b/include/etl/optional.h @@ -198,7 +198,7 @@ namespace etl //******************************************* template ETL_CONSTEXPR20_STL optional_impl(etl::in_place_t, std::initializer_list ilist, TArgs&&... args) - ETL_NOEXCEPT_IF((etl::is_nothrow_constructible, TArgs...>::value)) + ETL_NOEXCEPT_IF((etl::is_nothrow_constructible&, TArgs...>::value)) { storage.construct(ilist, etl::forward(args)...); } @@ -495,54 +495,38 @@ namespace etl storage.destroy(); } - //************************************************************************* - /// - //************************************************************************* - ETL_CONSTEXPR20_STL - T& emplace(const optional_impl& other) - { -#if ETL_IS_DEBUG_BUILD - ETL_ASSERT(other.has_value(), ETL_ERROR(optional_invalid)); -#endif - - storage.construct(other.value()); - - return storage.u.value; - } - #if ETL_USING_CPP11 && ETL_NOT_USING_STLPORT && !defined(ETL_OPTIONAL_FORCE_CPP03_IMPLEMENTATION) //************************************************************************* /// Emplaces a value from arbitrary constructor arguments. - /// Disabled (via SFINAE) if the first argument is an optional_impl (or a - /// derived type such as etl::optional) so that the dedicated - /// emplace(const optional_impl&) overload is selected instead. //************************************************************************* - template < typename U, typename... URest, - typename etl::enable_if< - !etl::is_base_of< optional_impl, typename etl::remove_cv< typename etl::remove_reference::type>::type>::value, int>::type = 0> - ETL_CONSTEXPR20_STL T& emplace(U&& first, URest&&... rest) ETL_NOEXCEPT_IF((etl::is_nothrow_constructible::value)) + template + ETL_CONSTEXPR20_STL T& emplace(Args&&... args) ETL_NOEXCEPT_IF((etl::is_nothrow_constructible::value)) { - storage.construct(etl::forward(first), etl::forward(rest)...); + storage.construct(etl::forward(args)...); return storage.u.value; } - //************************************************************************* - /// Emplaces with zero arguments, i.e. default construct emplace. - //************************************************************************* - ETL_CONSTEXPR20_STL - T& emplace() ETL_NOEXCEPT_IF(etl::is_nothrow_default_constructible::value) + #if ETL_HAS_INITIALIZER_LIST + //******************************************* + /// Emplaces a value from initializer_list and arbitrary constructor arguments. + //******************************************* + template &, Args...>::value, int>::type = 0 > + ETL_CONSTEXPR20_STL T& emplace(std::initializer_list ilist, Args&&... args) + ETL_NOEXCEPT_IF((etl::is_nothrow_constructible&, Args...>::value)) { - storage.construct(); + storage.construct(ilist, etl::forward(args)...); return storage.u.value; } + #endif #else //************************************************************************* /// Emplaces a value. /// 0 parameters. //************************************************************************* - T& emplace() + T& emplace() ETL_NOEXCEPT_IF((etl::is_nothrow_constructible::value)) { if (has_value()) { @@ -561,11 +545,7 @@ namespace etl /// 1 parameter. //************************************************************************* template - typename etl::enable_if< - !etl::is_base_of< this_type, typename etl::remove_cv< typename etl::remove_reference::type>::type>::value - && !etl::is_same< etl::optional, typename etl::remove_cv< typename etl::remove_reference< T1>::type>::type>::value, - T&>::type - emplace(const T1& value1) + T& emplace(const T1& value1) ETL_NOEXCEPT_IF((etl::is_nothrow_constructible::value)) { if (has_value()) { @@ -584,7 +564,7 @@ namespace etl /// 2 parameters. //************************************************************************* template - T& emplace(const T1& value1, const T2& value2) + T& emplace(const T1& value1, const T2& value2) ETL_NOEXCEPT_IF((etl::is_nothrow_constructible::value)) { if (has_value()) { @@ -603,7 +583,7 @@ namespace etl /// 3 parameters. //************************************************************************* template - T& emplace(const T1& value1, const T2& value2, const T3& value3) + T& emplace(const T1& value1, const T2& value2, const T3& value3) ETL_NOEXCEPT_IF((etl::is_nothrow_constructible::value)) { if (has_value()) { @@ -623,6 +603,7 @@ namespace etl //************************************************************************* template T& emplace(const T1& value1, const T2& value2, const T3& value3, const T4& value4) + ETL_NOEXCEPT_IF((etl::is_nothrow_constructible::value)) { if (has_value()) { @@ -1076,21 +1057,6 @@ namespace etl storage.destroy(); } - //************************************************************************* - /// - //************************************************************************* - ETL_CONSTEXPR20_STL - T& emplace(const optional_impl& other) - { -#if ETL_IS_DEBUG_BUILD - ETL_ASSERT(other.has_value(), ETL_ERROR(optional_invalid)); -#endif - - storage.construct(other.value()); - - return storage.u.value; - } - #if ETL_USING_CPP11 && ETL_NOT_USING_STLPORT && !defined(ETL_OPTIONAL_FORCE_CPP03_IMPLEMENTATION) //************************************************************************* /// Emplaces a value. @@ -1108,7 +1074,7 @@ namespace etl /// Emplaces a value. /// 0 parameters. //************************************************************************* - T& emplace() + T& emplace() ETL_NOEXCEPT { if (has_value()) { @@ -1127,11 +1093,7 @@ namespace etl /// 1 parameter. //************************************************************************* template - typename etl::enable_if< - !etl::is_base_of< this_type, typename etl::remove_cv< typename etl::remove_reference::type>::type>::value - && !etl::is_same< etl::optional, typename etl::remove_cv< typename etl::remove_reference< T1>::type>::type>::value, - T&>::type - emplace(const T1& value1) + T& emplace(const T1& value1) ETL_NOEXCEPT { if (has_value()) { @@ -1150,7 +1112,7 @@ namespace etl /// 2 parameters. //************************************************************************* template - T& emplace(const T1& value1, const T2& value2) + T& emplace(const T1& value1, const T2& value2) ETL_NOEXCEPT { if (has_value()) { @@ -1169,7 +1131,7 @@ namespace etl /// 3 parameters. //************************************************************************* template - T& emplace(const T1& value1, const T2& value2, const T3& value3) + T& emplace(const T1& value1, const T2& value2, const T3& value3) ETL_NOEXCEPT { if (has_value()) { @@ -1188,7 +1150,7 @@ namespace etl /// 4 parameters. //************************************************************************* template - T& emplace(const T1& value1, const T2& value2, const T3& value3, const T4& value4) + T& emplace(const T1& value1, const T2& value2, const T3& value3, const T4& value4) ETL_NOEXCEPT { if (has_value()) { @@ -1416,7 +1378,7 @@ namespace etl //******************************************* template ETL_CONSTEXPR14 explicit optional(etl::in_place_t, std::initializer_list ilist, TArgs&&... args) - ETL_NOEXCEPT_IF((etl::is_nothrow_constructible, TArgs...>::value)) + ETL_NOEXCEPT_IF((etl::is_nothrow_constructible&, TArgs...>::value)) : impl_t(etl::in_place_t{}, ilist, etl::forward(args)...) { } @@ -1426,7 +1388,7 @@ namespace etl //******************************************* template ETL_CONSTEXPR20_STL explicit optional(etl::in_place_t, std::initializer_list ilist, TArgs&&... args) - ETL_NOEXCEPT_IF((etl::is_nothrow_constructible, TArgs...>::value)) + ETL_NOEXCEPT_IF((etl::is_nothrow_constructible&, TArgs...>::value)) : impl_t(etl::in_place_t{}, ilist, etl::forward(args)...) { } diff --git a/test/test_optional.cpp b/test/test_optional.cpp index 04ad9574..e1e05f9c 100644 --- a/test/test_optional.cpp +++ b/test/test_optional.cpp @@ -153,7 +153,7 @@ namespace #if ETL_USING_CPP14 //************************************************************************* - TEST(test_emplace_construction_cpp14) + TEST(test_in_place_construction_cpp14) { constexpr etl::optional opt(etl::in_place_t{}, 1); @@ -165,7 +165,7 @@ namespace #if ETL_USING_CPP20 && ETL_USING_STL //************************************************************************* - TEST(test_emplace_construction_cpp20) + TEST(test_in_place_construction_cpp20) { struct TestData { @@ -255,13 +255,41 @@ namespace //************************************************************************* TEST(test_emplace_return) { - etl::optional data; + // not fundamental + { + etl::optional data; - DataM* datam = &data.emplace(1U); - CHECK_EQUAL(datam, &data.value()); - CHECK(datam != nullptr); + DataM* datam_ptr = &data.emplace(1U); + CHECK_EQUAL(datam_ptr, &data.value()); + CHECK(datam_ptr != nullptr); + } + + // fundamental + { + etl::optional data; + + int* data_ptr = &data.emplace(1); + CHECK_EQUAL(data_ptr, &data.value()); + CHECK(data_ptr != nullptr); + } } + //************************************************************************* +#if !defined(ETL_FORCE_TEST_CPP03_IMPLEMENTATION) + TEST(test_emplace_initializer_list) + { + etl::optional data; + + data.emplace({1, 2}, 10, 20, 30); + CHECK_TRUE(data.has_value()); + CHECK_EQUAL(data->arr[0], 1); + CHECK_EQUAL(data->arr[1], 2); + CHECK_EQUAL(data->a, 10); + CHECK_EQUAL(data->b, 20); + CHECK_EQUAL(data->c, 30); + } +#endif + //************************************************************************* TEST(test_moveable_not_fundamental) { @@ -1120,11 +1148,11 @@ namespace CHECK_EQUAL(1, (*opt2)[0]); CHECK_EQUAL(20, (*opt2)[1]); - etl::optional opt3; + etl::optional> opt3; opt3.emplace(create_optional_issue_1171()); CHECK_TRUE(opt3.has_value()); - CHECK_EQUAL(1, (*opt3)[0]); - CHECK_EQUAL(20, (*opt3)[1]); + CHECK_EQUAL(1, (**opt3)[0]); + CHECK_EQUAL(20, (**opt3)[1]); } //************************************************************************* @@ -1542,12 +1570,38 @@ namespace // make_optional #3 { - static_assert(noexcept(etl::make_optional({1, 2, 3})), "make_optional(1,2,3) should be nothrow"); - static_assert(noexcept(etl::make_optional({1, 2, 3})), "make_optional(1,2,3) should be nothrow"); + static_assert(noexcept(etl::make_optional({1, 2, 3})), "make_optional({1,2,3}) should be nothrow"); + static_assert(noexcept(etl::make_optional({1, 2, 3})), "make_optional({1,2,3}) should be nothrow"); static_assert(!noexcept(etl::make_optional({1, 2, 3})), "make_optional({1,2,3}) should NOT be nothrow"); static_assert(!noexcept(etl::make_optional({1, 2, 3})), "make_optional({1,2,3}) should NOT be nothrow"); } } + + TEST(test_emplace_nothrow) + { + // emplace #1 + { + etl::optional fundamental{}; + static_assert(noexcept(fundamental.emplace()), "optional::emplace() should always be nothrow"); + + etl::optional nothrowAtAll{}; + static_assert(noexcept(nothrowAtAll.emplace()), "optional::emplace() should be nothrow"); + + etl::optional throwingAll{}; + static_assert(!noexcept(throwingAll.emplace()), "optional::emplace() should NOT be nothrow"); + } + + // emplace #2 (initializer_list) + #if !defined(ETL_FORCE_TEST_CPP03_IMPLEMENTATION) + { + etl::optional nothrowAtAll{}; + static_assert(noexcept(nothrowAtAll.emplace({1, 2, 3})), "optional::emplace({1, 2, 3}) should be nothrow"); + + etl::optional throwingAll{}; + static_assert(!noexcept(throwingAll.emplace({1, 2, 3})), "optional::emplace({1, 2, 3}) should NOT be nothrow"); + } + #endif + } #endif } } // namespace