More constexpr conversions

This commit is contained in:
Denis Blank 2018-01-30 00:13:54 +01:00
parent 933d773c4c
commit fb4eb379ca
2 changed files with 65 additions and 42 deletions

View File

@ -333,7 +333,7 @@ auto make_all_result_submitter(Callback&& callback,
/// A callable object to merge multiple signature hints together
struct entry_merger {
template <typename... T>
constexpr auto operator()(T&... entries) noexcept {
constexpr auto operator()(T&... entries) const noexcept {
return traits::merge(hints::hint_of(traits::identity_of(entries))...);
}
};
@ -400,37 +400,53 @@ auto make_any_result_submitter(Callback&& callback) {
std::forward<decltype(callback)>(callback));
}
template <typename T, typename... Args>
constexpr T first_of(traits::identity<T, Args...>) noexcept;
template <typename T>
struct check_pack_empty {
static constexpr auto const is_empty =
(decltype(traits::pack_size_of(std::declval<T>())){} ==
traits::size_constant_of<0>());
static_assert(is_empty.value, "Expected all continuations to have the same"
"count of arguments!");
};
template <typename Signature, typename... Args>
constexpr auto common_result_of(Signature signature,
hints::signature_hint_tag<>, Args... /*args*/) {
/// Assert that the other signatures are empty too which means all signatures
/// had the same size.
traits::static_for_each_in(traits::identity<Args...>{}, [&](auto rest) {
auto is_empty =
(traits::pack_size_of(rest) == traits::size_constant_of<0>());
static_assert(is_empty.value, "Expected all continuations to have the same"
"count of arguments!");
});
return signature;
}
/// A callable object to determine the shared result between all continuations
struct determine_shared_result {
template <typename... T>
constexpr auto operator()(T&... args) const noexcept {
return common_result_of(hints::signature_hint_tag<>{},
hints::hint_of(traits::identity_of(args))...);
}
/// Determine the common result between all continuation which are chained
/// with an `any` strategy, consider two continuations:
/// c1 with `void(int)` and c2 with `void(float)`, the common result shared
/// between both continuations is `void(int)`.
template <typename Signature, typename First, typename... Args>
constexpr auto common_result_of(Signature signature, First first,
Args... args) {
using Common =
traits::identity<std::common_type_t<decltype(first_of(first)),
decltype(first_of(args))...>>;
private:
template <typename Signature, typename... Args>
static constexpr auto common_result_of(Signature signature,
hints::signature_hint_tag<>,
Args... /*args*/) {
/// Assert that the other signatures are empty too which means all
/// signatures had the same size.
std::initializer_list<int>{0, ((void)check_pack_empty<Args>{}, 0)...};
return signature;
}
return common_result_of(traits::push(signature, Common{}),
traits::pop_first(first), traits::pop_first(args)...);
}
template <typename T, typename... Args>
static constexpr T first_of(traits::identity<T, Args...>) noexcept;
/// Determine the common result between all continuation which are chained
/// with an `any` strategy, consider two continuations:
/// c1 with `void(int)` and c2 with `void(float)`, the common result shared
/// between both continuations is `void(int)`.
template <typename Signature, typename First, typename... Args>
static constexpr auto common_result_of(Signature signature, First first,
Args... args) {
using common_type =
traits::identity<std::common_type_t<decltype(first_of(first)),
decltype(first_of(args))...>>;
return common_result_of(traits::push(signature, common_type{}),
traits::pop_first(first),
traits::pop_first(args)...);
}
};
/// Finalizes the any logic of a given composition
template <typename Data>
@ -441,11 +457,8 @@ auto finalize_composition(
auto composition = base::attorney::consume_data(std::move(continuation));
// Determine the shared result between all continuations
auto signature = traits::unpack(composition, [](auto const&... args) {
return common_result_of(hints::signature_hint_tag<>{},
hints::hint_of(traits::identity_of(args))...);
});
constexpr auto signature =
traits::unpack(composition, determine_shared_result{});
return base::attorney::create(
[composition = std::move(composition)](auto&& callback) mutable {

View File

@ -203,6 +203,18 @@ constexpr auto static_if_impl(std::false_type, Type&& type,
FalseCallback&& falseCallback) {
return std::forward<FalseCallback>(falseCallback)(std::forward<Type>(type));
}
/// Applies the given callable to all objects in a sequence
template <typename C>
struct apply_to_all {
C callable;
template <typename... T>
constexpr void operator()(T&&... args) {
(void)std::initializer_list<int>{
0, ((void)callable(std::forward<decltype(args)>(args)), 0)...};
}
};
} // namespace detail
/// Returns the pack size of the given type
@ -340,22 +352,20 @@ constexpr auto unpack(F&& firstSequenceable, S&& secondSequenceable,
}
/// Applies the handler function to each element contained in the sequenceable
// TODO Maybe crashes MSVC in constexpr mode
template <typename Sequenceable, typename Handler>
constexpr void static_for_each_in(Sequenceable&& sequenceable,
Handler&& handler) {
unpack(
std::forward<Sequenceable>(sequenceable), [&](auto&&... entries) mutable {
// Apply the consume function to every entry inside the pack
(void)std::initializer_list<int>{
0, ((void)handler(std::forward<decltype(entries)>(entries)), 0)...};
});
unpack(std::forward<Sequenceable>(sequenceable),
detail::apply_to_all<std::decay_t<Handler>>{
std::forward<Handler>(handler)});
}
/// Adds the given type at the back of the left sequenceable
template <typename Left, typename Element>
constexpr auto push(Left&& left, Element&& element) {
return unpack(std::forward<Left>(left), [&](auto&&... leftArgs) {
return std::make_tuple(std::forward<decltype(leftArgs)>(leftArgs)...,
return unpack(std::forward<Left>(left), [&](auto&&... args) {
return std::make_tuple(std::forward<decltype(args)>(args)...,
std::forward<Element>(element));
});
}