Add void to Switch

This commit is contained in:
sha512sum 2024-07-15 16:17:00 +00:00
parent eaddebf1e5
commit e15d520cfa
2 changed files with 34 additions and 14 deletions

View file

@ -20,4 +20,11 @@ auto main() -> int {
[] { [] {
return 42; return 42;
}) == 42); }) == 42);
static_assert([] {
int response{};
utempl::Switch(utempl::Tuple{2, 1, 0}, utempl::Tuple{0, 1, 2}, 0, [&](int value) {
response = value + 1;
});
return response;
}() == 3);
}; };

View file

@ -644,11 +644,14 @@ constexpr auto Enumerate(Tuple&& tuple) {
}; };
template <typename T> template <typename T>
requires requires { T{}; } requires std::same_as<T, void> || requires { T{}; }
constexpr auto kDefaultCreator = [] { constexpr auto kDefaultCreator = [] {
return T{}; return T{};
}; };
template <>
constexpr auto kDefaultCreator<void> = [] {};
namespace impl { namespace impl {
template <typename Key, typename KeysTuple> template <typename Key, typename KeysTuple>
@ -657,29 +660,39 @@ concept ComparableSwitchConcept = decltype(Unpack(std::declval<KeysTuple>(), []<
}))::kValue; }))::kValue;
template <typename F, typename ValuesTuple, typename R> template <typename F, typename ValuesTuple, typename R>
concept CallableSwitchConcept = decltype(Unpack(std::declval<ValuesTuple>(), []<typename... Ts>(Ts&&...) { concept CallableSwitchConcept = std::same_as<R, void> || decltype(Unpack(std::declval<ValuesTuple>(), []<typename... Ts>(Ts&&...) {
return kWrapper<(std::convertible_to<std::invoke_result_t<F, Ts>, std::optional<R>> && ...)>; return kWrapper<(std::convertible_to<std::invoke_result_t<F, Ts>, std::optional<R>> && ...)>;
}))::kValue; }))::kValue;
} // namespace impl } // namespace impl
template <std::move_constructible R, template <typename R = void,
TupleLike KeysTuple, TupleLike KeysTuple,
TupleLike ValuesTuple, TupleLike ValuesTuple,
impl::ComparableSwitchConcept<KeysTuple> Key, impl::ComparableSwitchConcept<KeysTuple> Key,
impl::CallableSwitchConcept<ValuesTuple, R> F, impl::CallableSwitchConcept<ValuesTuple, R> F,
std::invocable Default = decltype(kDefaultCreator<R>)> std::invocable Default = decltype(kDefaultCreator<R>)>
constexpr auto Switch(KeysTuple&& keysTuple, ValuesTuple&& valuesTuple, Key&& key, F&& f, Default&& def = {}) { constexpr auto Switch(KeysTuple&& keysTuple, ValuesTuple&& valuesTuple, Key&& key, F&& f, Default&& def = {}) -> R
requires std::move_constructible<R> || std::same_as<R, void>
{
return Unpack(std::forward<KeysTuple>(keysTuple), [&]<typename... Keys>(Keys&&... keys) { return Unpack(std::forward<KeysTuple>(keysTuple), [&]<typename... Keys>(Keys&&... keys) {
return Unpack(std::forward<ValuesTuple>(valuesTuple), [&]<typename... Values>(Values&&... values) { return Unpack(std::forward<ValuesTuple>(valuesTuple), [&]<typename... Values>(Values&&... values) {
return *FirstOf(Tuple{[&] { if constexpr(std::same_as<R, void>) {
return std::forward<Keys>(keys) == std::forward<Key>(key) ? std::forward<F>(f)(std::forward<Values>(values)) FirstOf(Tuple{[&] {
: std::optional<R>{}; return std::forward<Keys>(keys) == std::forward<Key>(key) ? (std::forward<F>(f)(std::forward<Values>(values)), true)
}...}, : false;
std::optional<R>{}) }...},
.or_else([&] -> std::optional<R> { false);
return std::forward<Default>(def)(); } else {
}); return *FirstOf(Tuple{[&] {
return std::forward<Keys>(keys) == std::forward<Key>(key) ? std::forward<F>(f)(std::forward<Values>(values))
: std::optional<R>{};
}...},
std::optional<R>{})
.or_else([&] -> std::optional<R> {
return std::forward<Default>(def)();
});
};
}); });
}); });
}; };