Skip to content

Instantly share code, notes, and snippets.

@glukianets
Last active November 27, 2019 15:51
Show Gist options
  • Save glukianets/a39e57c95e8a035c47c3d9a151ac5b68 to your computer and use it in GitHub Desktop.
Save glukianets/a39e57c95e8a035c47c3d9a151ac5b68 to your computer and use it in GitHub Desktop.
Performs any kind of accumulating operation over any amount of variably nested arrays and tuples. Can be extended to support more types.
namespace impl {
template<typename T>
struct FlatTypeTraits;
template<typename T, size_t L>
struct FlatTypeTraits<std::array<T, L>> {
template<typename AccT, typename CallableT>
static constexpr void acc(const std::array<T, L> &array, AccT &acc, CallableT &&callable) {
for (const T &element : array)
FlatTypeTraits<T>::acc(element, acc, callable);
}
};
template<typename T>
struct FlatTypeTraits {
template<typename AccT, typename CallableT>
static constexpr void acc(const T &value, AccT &acc, CallableT &&callable) { std::invoke(callable, acc, value); }
};
template<typename ... T>
struct FlatTypeTraits<std::tuple<T...>> {
template<typename AccT, typename CallableT>
static constexpr auto acc(const std::tuple<T...> &tuple, AccT &acc, CallableT &&callable) {
accHelper(tuple, acc, callable);
}
template<size_t I = 0, typename AccT, typename CallableT, typename ...AT>
static constexpr auto accHelper(const std::tuple<AT...> &tuple, AccT &acc, CallableT &&callable) {
if constexpr (I < sizeof...(T)) {
FlatTypeTraits<std::tuple_element_t<I, std::tuple<AT...>>>::acc(std::get<I>(tuple), acc, callable);
accHelper<I + 1>(tuple, acc, callable);
}
}
};
} // impl
template<typename T, typename AccT, typename CallableT>
auto flat_accumulate(T &&v, AccT acc, CallableT &&callable) -> AccT {
impl::FlatTypeTraits<std::remove_reference_t<T>>::acc(std::forward<T>(v), acc, callable);
return acc;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment