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 /// A callable object to merge multiple signature hints together
struct entry_merger { struct entry_merger {
template <typename... T> 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))...); 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)); std::forward<decltype(callback)>(callback));
} }
template <typename T, typename... Args> template <typename T>
constexpr T first_of(traits::identity<T, Args...>) noexcept; struct check_pack_empty {
static constexpr auto const is_empty =
template <typename Signature, typename... Args> (decltype(traits::pack_size_of(std::declval<T>())){} ==
constexpr auto common_result_of(Signature signature, traits::size_constant_of<0>());
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" static_assert(is_empty.value, "Expected all continuations to have the same"
"count of arguments!"); "count of arguments!");
}); };
return signature;
}
/// Determine the common result between all continuation which are chained /// A callable object to determine the shared result between all continuations
/// with an `any` strategy, consider two continuations: struct determine_shared_result {
/// c1 with `void(int)` and c2 with `void(float)`, the common result shared template <typename... T>
/// between both continuations is `void(int)`. constexpr auto operator()(T&... args) const noexcept {
template <typename Signature, typename First, typename... Args> return common_result_of(hints::signature_hint_tag<>{},
constexpr auto common_result_of(Signature signature, First first, hints::hint_of(traits::identity_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;
}
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) { Args... args) {
using Common = using common_type =
traits::identity<std::common_type_t<decltype(first_of(first)), traits::identity<std::common_type_t<decltype(first_of(first)),
decltype(first_of(args))...>>; decltype(first_of(args))...>>;
return common_result_of(traits::push(signature, Common{}), return common_result_of(traits::push(signature, common_type{}),
traits::pop_first(first), traits::pop_first(args)...); traits::pop_first(first),
} traits::pop_first(args)...);
}
};
/// Finalizes the any logic of a given composition /// Finalizes the any logic of a given composition
template <typename Data> template <typename Data>
@ -441,11 +457,8 @@ auto finalize_composition(
auto composition = base::attorney::consume_data(std::move(continuation)); auto composition = base::attorney::consume_data(std::move(continuation));
// Determine the shared result between all continuations constexpr auto signature =
auto signature = traits::unpack(composition, [](auto const&... args) { traits::unpack(composition, determine_shared_result{});
return common_result_of(hints::signature_hint_tag<>{},
hints::hint_of(traits::identity_of(args))...);
});
return base::attorney::create( return base::attorney::create(
[composition = std::move(composition)](auto&& callback) mutable { [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) { FalseCallback&& falseCallback) {
return std::forward<FalseCallback>(falseCallback)(std::forward<Type>(type)); 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 } // namespace detail
/// Returns the pack size of the given type /// 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 /// Applies the handler function to each element contained in the sequenceable
// TODO Maybe crashes MSVC in constexpr mode
template <typename Sequenceable, typename Handler> template <typename Sequenceable, typename Handler>
constexpr void static_for_each_in(Sequenceable&& sequenceable, constexpr void static_for_each_in(Sequenceable&& sequenceable,
Handler&& handler) { Handler&& handler) {
unpack( unpack(std::forward<Sequenceable>(sequenceable),
std::forward<Sequenceable>(sequenceable), [&](auto&&... entries) mutable { detail::apply_to_all<std::decay_t<Handler>>{
// Apply the consume function to every entry inside the pack std::forward<Handler>(handler)});
(void)std::initializer_list<int>{
0, ((void)handler(std::forward<decltype(entries)>(entries)), 0)...};
});
} }
/// Adds the given type at the back of the left sequenceable /// Adds the given type at the back of the left sequenceable
template <typename Left, typename Element> template <typename Left, typename Element>
constexpr auto push(Left&& left, Element&& element) { constexpr auto push(Left&& left, Element&& element) {
return unpack(std::forward<Left>(left), [&](auto&&... leftArgs) { return unpack(std::forward<Left>(left), [&](auto&&... args) {
return std::make_tuple(std::forward<decltype(leftArgs)>(leftArgs)..., return std::make_tuple(std::forward<decltype(args)>(args)...,
std::forward<Element>(element)); std::forward<Element>(element));
}); });
} }