diff --git a/docs/containers/lists/list.md b/docs/containers/lists/list.md index 8ae13fd3..0ae64e39 100644 --- a/docs/containers/lists/list.md +++ b/docs/containers/lists/list.md @@ -69,13 +69,15 @@ Defines data as an list of `int`, of length `10`, containing the supplied data. ## Make template **C++11 and above** ```cpp -template -constexpr auto make_list(TValues&&... values) +template +constexpr auto make_list(T&&... t) -> etl::list, sizeof...(T)> ``` +The element type is deduced as the common type of the arguments. + ### Example ```cpp -auto data = etl::make_list(0, 1, 2, 3, 4, 5, 6, 7, 8, 9); +auto data = etl::make_list(0, 1, 2, 3, 4, 5, 6, 7, 8, 9); ``` ## Member types diff --git a/include/etl/list.h b/include/etl/list.h index c2bbdfc2..7be34fcc 100644 --- a/include/etl/list.h +++ b/include/etl/list.h @@ -2219,7 +2219,7 @@ namespace etl //************************************************************************* #if ETL_USING_CPP11 && ETL_HAS_INITIALIZER_LIST template - constexpr auto make_list(T... t) -> etl::list, sizeof...(T)> + constexpr auto make_list(T&&... t) -> etl::list, sizeof...(T)> { return {etl::forward(t)...}; } diff --git a/test/test_list.cpp b/test/test_list.cpp index 00574f24..767166e7 100644 --- a/test/test_list.cpp +++ b/test/test_list.cpp @@ -2272,5 +2272,110 @@ namespace CHECK_EQUAL(ItemNDC("F"), *itr++); } #endif + + //************************************************************************* +#if ETL_HAS_INITIALIZER_LIST + // Const-qualified lvalue arguments must be accepted and must not affect the + // deduced element type (the deduced reference types decay via common_type). + TEST(test_make_list_from_const_lvalues_of_element_type) + { + static const char static_const_lvalue = 42; + const char local_const_lvalue = 43; + char mutable_lvalue = 44; + + auto data = etl::make_list(static_const_lvalue, local_const_lvalue, mutable_lvalue); + + CHECK((std::is_same, decltype(data)>::value)); + + auto itr = data.begin(); + CHECK_EQUAL(42, *itr++); + CHECK_EQUAL(43, *itr++); + CHECK_EQUAL(44, *itr++); + } +#endif + + //************************************************************************* +#if ETL_HAS_INITIALIZER_LIST + TEST(test_make_list_common_type_from_mixed_types) + { + auto data = etl::make_list(1, 2L, 3); + + CHECK((std::is_same, decltype(data)>::value)); + + auto itr = data.begin(); + CHECK_EQUAL(1L, *itr++); + CHECK_EQUAL(2L, *itr++); + CHECK_EQUAL(3L, *itr++); + } +#endif + + //************************************************************************* +#if ETL_HAS_INITIALIZER_LIST + struct CopyMoveCounted + { + explicit CopyMoveCounted(int value_) + : value(value_) + { + } + + CopyMoveCounted(const CopyMoveCounted& other) + : value(other.value) + { + ++copy_count; + } + + CopyMoveCounted(CopyMoveCounted&& other) + : value(other.value) + { + ++move_count; + } + + int value; + + static size_t copy_count; + static size_t move_count; + }; + + size_t CopyMoveCounted::copy_count = 0; + size_t CopyMoveCounted::move_count = 0; + + // The arguments must be forwarded into the initializer list, not taken by + // value: a by-value parameter pack costs an extra move per argument. + // Each element is then copied from the initializer_list backing array into + // its list node, which is why lvalue arguments count two copies. + TEST(test_make_list_argument_copy_and_move_counts) + { + const CopyMoveCounted const_lvalue(1); + CopyMoveCounted mutable_lvalue(2); + + CopyMoveCounted::copy_count = 0; + CopyMoveCounted::move_count = 0; + + auto data = etl::make_list(const_lvalue, mutable_lvalue); + + CHECK_EQUAL(4U, CopyMoveCounted::copy_count); + #if ETL_USING_CPP17 + // The exact move counts rely on guaranteed copy elision. Before C++17 the + // returned list may be move-constructed once more, which moves each element, + // so only the copy counts are checked there. + CHECK_EQUAL(0U, CopyMoveCounted::move_count); + #endif + + CopyMoveCounted::copy_count = 0; + CopyMoveCounted::move_count = 0; + + auto data2 = etl::make_list(CopyMoveCounted(3)); + + CHECK_EQUAL(1U, CopyMoveCounted::copy_count); + #if ETL_USING_CPP17 + CHECK_EQUAL(1U, CopyMoveCounted::move_count); + #endif + + auto itr = data.begin(); + CHECK_EQUAL(1, (*itr++).value); + CHECK_EQUAL(2, (*itr).value); + CHECK_EQUAL(3, data2.begin()->value); + } +#endif } } // namespace