From eea806bcc90572c5f2f4c91426e51172d3a0108f Mon Sep 17 00:00:00 2001 From: Kp Date: Mon, 1 Nov 2021 03:37:20 +0000 Subject: [PATCH] Pass underlying index_type through zip() If std::common_type... finds a common index_type among all the zipped ranges, pass that common type through as zip<...>::index_type. Otherwise, set zip<...>::index_type to void. This allows enumerate(zip(...))) to report a better index_type. --- common/main/d_zip.h | 21 +++++++++++++++++++-- common/unittest/zip.cpp | 24 ++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/common/main/d_zip.h b/common/main/d_zip.h index b83b46497..a1529d482 100644 --- a/common/main/d_zip.h +++ b/common/main/d_zip.h @@ -78,6 +78,22 @@ struct check_static_size_pair : s { }; +void range_index_type(...); + +template < + typename... range_type, + /* If any `range_type::index_type` is not defined, fail. + * If there is no common_type among all the + * `range_type::index_type`, fail. + */ + typename index_type = typename std::common_type::type::index_type &>::type...>::type, + /* If the common_type `index_type` is not a suitable argument to all + * `range_type::operator[]()`, fail. + */ + typename = std::void_t().operator[](std::declval()))...> + > +index_type range_index_type(std::tuple *); + } } @@ -164,13 +180,14 @@ public: } }; -template +template class zip : zip_iterator { range0_iterator_type m_end; public: using range_owns_iterated_storage = std::false_type; using iterator = zip_iterator; + using index_type = range_index_type; template constexpr zip(range0 &&r0, rangeN &&... rN) : iterator(std::begin(r0), std::begin(rN)...), m_end(std::end(r0)) @@ -201,4 +218,4 @@ public: }; template -zip(range0 &&r0, rangeN &&... rN) -> zip; +zip(range0 &&r0, rangeN &&... rN) -> zip *>(nullptr))), decltype(std::begin(r0)), decltype(std::begin(rN))...>; diff --git a/common/unittest/zip.cpp b/common/unittest/zip.cpp index a47ce9e88..eadda19f8 100644 --- a/common/unittest/zip.cpp +++ b/common/unittest/zip.cpp @@ -65,3 +65,27 @@ BOOST_AUTO_TEST_CASE(zip_xrange) BOOST_TEST(std::get<0>(v) == 0); } } + +/* Type system tests can be done at compile-time. Applying them as + * static_assert can produce a better error message than letting it fail + * at runtime. + */ +template +struct assert_index_type : std::true_type +{ + static_assert(std::is_same::value); +}; + +static_assert(assert_index_type>(), std::declval>()))>::value); + +template +struct custom_index_type : std::array +{ + using index_type = T; + void operator[](typename std::remove_reference::type); +}; +enum class e1 : unsigned char; +enum class e2 : unsigned char; + +static_assert(assert_index_type&>(), std::declval&>()))>::value); +static_assert(assert_index_type&>(), std::declval&>()))>::value);