Implement the missing checks for container categories

This commit is contained in:
Denis Blank 2018-02-06 02:18:28 +01:00
parent 09f9da3e0e
commit f0b25956b9
3 changed files with 40 additions and 18 deletions

View File

@ -71,19 +71,19 @@ namespace cti {
///
template <typename Mapper, typename... T>
auto map_pack(Mapper&& mapper, T&&... pack) {
return detail::traversal::apply_pack_transform(
detail::traversal::strategy_remap_tag{}, std::forward<Mapper>(mapper),
std::forward<T>(pack)...);
return detail::traversal::transform(detail::traversal::strategy_remap_tag{},
std::forward<Mapper>(mapper),
std::forward<T>(pack)...);
}
/// Indicate that the result shall be spread across the parent container
/// if possible. This can be used to create a mapper function used
/// in map_pack that maps one element to an arbitrary count (1:n).
template <typename... T>
constexpr auto spread_this(T&&... args) {
return detail::traversal::spreading::spread_box<
typename std::decay<T>::type...>(
std::make_tuple(std::forward<T>(args)...));
constexpr auto spread_this(T&&... args) noexcept(
noexcept(std::make_tuple(std::forward<T>(args)...))) {
using type = detail::traversal::spreading::spread_box<std::decay_t<T>...>;
return type(std::make_tuple(std::forward<T>(args)...));
}
/// Traverses the pack with the given visitor.
@ -94,9 +94,9 @@ constexpr auto spread_this(T&&... args) {
/// See `map_pack` for a detailed description.
template <typename Mapper, typename... T>
void traverse_pack(Mapper&& mapper, T&&... pack) {
detail::traversal::apply_pack_transform(
detail::traversal::strategy_traverse_tag{}, std::forward<Mapper>(mapper),
std::forward<T>(pack)...);
detail::traversal::transform(detail::traversal::strategy_traverse_tag{},
std::forward<Mapper>(mapper),
std::forward<T>(pack)...);
}
} // namespace cti

View File

@ -31,9 +31,36 @@
#ifndef CONTINUABLE_DETAIL_CONTAINER_CATEGORY_HPP_INCLUDED
#define CONTINUABLE_DETAIL_CONTAINER_CATEGORY_HPP_INCLUDED
#include <tuple>
#include <type_traits>
#include <continuable/detail/traits.hpp>
namespace cti {
namespace detail {
namespace traversal {
namespace detail {
/// Deduces to a true type if the given parameter T
/// has a begin() and end() method.
// TODO Find out whether we should use std::begin and std::end instead, which
// could cause issues with plain arrays.
template <typename T, typename = void>
struct is_range : std::false_type {};
template <typename T>
struct is_range<T, traits::void_t<decltype(std::declval<T>().begin() ==
std::declval<T>().end())>>
: std::true_type {};
/// Deduces to a true type if the given parameter T
/// is accessible through std::tuple_size.
template <typename T, typename = void>
struct is_tuple_like : std::false_type {};
template <typename T>
struct is_tuple_like<T, traits::void_t<decltype(std::tuple_size<T>::value)>>
: std::true_type {};
} // namespace detail
/// A tag for dispatching based on the tuple like
/// or container properties of a type.
template <bool IsContainer, bool IsTupleLike>
@ -42,9 +69,8 @@ struct container_category_tag {};
/// Deduces to the container_category_tag of the given type T.
template <typename T>
using container_category_of_t =
container_category_tag<false, // TODO traits::is_range<T>::value,
false // TODO traits::is_tuple_like<T>::value
>;
container_category_tag<detail::is_range<T>::value,
detail::is_tuple_like<T>::value>;
} // namespace traversal
} // namespace detail
} // namespace cti

View File

@ -833,11 +833,7 @@ public:
/// Traverses the given pack with the given mapper and strategy
template <typename Strategy, typename Mapper, typename... T>
auto apply_pack_transform(Strategy strategy, Mapper&& mapper, T&&... pack)
-> decltype(
std::declval<
mapping_helper<Strategy, typename std::decay<Mapper>::type>>()
.init_traverse(strategy, std::forward<T>(pack)...)) {
auto transform(Strategy strategy, Mapper&& mapper, T&&... pack) {
mapping_helper<Strategy, typename std::decay<Mapper>::type> helper(
std::forward<Mapper>(mapper));
return helper.init_traverse(strategy, std::forward<T>(pack)...);