Pass underlying index_type through zip()
If std::common_type<range::index_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.
This commit is contained in:
parent
51a76f74be
commit
eea806bcc9
|
@ -78,6 +78,22 @@ struct check_static_size_pair<range0, rangeN, range0_extent, std::nullptr_t> : 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<typename std::remove_reference<typename std::remove_reference<range_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<decltype(std::declval<range_type &>().operator[](std::declval<index_type>()))...>
|
||||
>
|
||||
index_type range_index_type(std::tuple<range_type...> *);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -164,13 +180,14 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
template <typename range0_iterator_type, typename... rangeN_iterator_type>
|
||||
template <typename range_index_type, typename range0_iterator_type, typename... rangeN_iterator_type>
|
||||
class zip : zip_iterator<range0_iterator_type, rangeN_iterator_type...>
|
||||
{
|
||||
range0_iterator_type m_end;
|
||||
public:
|
||||
using range_owns_iterated_storage = std::false_type;
|
||||
using iterator = zip_iterator<range0_iterator_type, rangeN_iterator_type...>;
|
||||
using index_type = range_index_type;
|
||||
template <typename range0, typename... rangeN>
|
||||
constexpr zip(range0 &&r0, rangeN &&... rN) :
|
||||
iterator(std::begin(r0), std::begin(rN)...), m_end(std::end(r0))
|
||||
|
@ -201,4 +218,4 @@ public:
|
|||
};
|
||||
|
||||
template <typename range0, typename... rangeN>
|
||||
zip(range0 &&r0, rangeN &&... rN) -> zip<decltype(std::begin(r0)), decltype(std::begin(rN))...>;
|
||||
zip(range0 &&r0, rangeN &&... rN) -> zip<decltype(d_zip::detail::range_index_type(static_cast<std::tuple<range0, rangeN...> *>(nullptr))), decltype(std::begin(r0)), decltype(std::begin(rN))...>;
|
||||
|
|
|
@ -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 <typename Expected, typename zip_type, typename index_type = typename zip_type::index_type>
|
||||
struct assert_index_type : std::true_type
|
||||
{
|
||||
static_assert(std::is_same<Expected, index_type>::value);
|
||||
};
|
||||
|
||||
static_assert(assert_index_type<void, decltype(zip(std::declval<std::array<int, 1>>(), std::declval<std::array<float, 1>>()))>::value);
|
||||
|
||||
template <typename T>
|
||||
struct custom_index_type : std::array<int, 1>
|
||||
{
|
||||
using index_type = T;
|
||||
void operator[](typename std::remove_reference<T>::type);
|
||||
};
|
||||
enum class e1 : unsigned char;
|
||||
enum class e2 : unsigned char;
|
||||
|
||||
static_assert(assert_index_type<e1, decltype(zip(std::declval<custom_index_type<e1>&>(), std::declval<custom_index_type<e1>&>()))>::value);
|
||||
static_assert(assert_index_type<void, decltype(zip(std::declval<custom_index_type<e1>&>(), std::declval<custom_index_type<e2>&>()))>::value);
|
||||
|
|
Loading…
Reference in a new issue