better example
This commit is contained in:
86
include/sp/protocol/Templates.h
Normal file
86
include/sp/protocol/Templates.h
Normal file
@@ -0,0 +1,86 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace sp {
|
||||
|
||||
/// @brief Default case, see field_index specialization for implementation details
|
||||
template <size_t N, typename T, template <size_t, typename> typename U, typename = void>
|
||||
static constexpr size_t field_index = 0;
|
||||
|
||||
/// @brief A templated size_t that counts the number of existing classes U with a "field_name" member
|
||||
/// @tparam N Current counter for recursion (user should always call it with 0)
|
||||
/// @tparam T Can be any type, must be different for each field we want to be counted later (used because we can't have a empty
|
||||
/// template<> specialization nested in a class)
|
||||
/// @tparam U The templated class that will be searched for match
|
||||
template <size_t N, typename T, template <size_t, typename> typename U>
|
||||
static constexpr size_t field_index<N, T, U, std::void_t<decltype(U<N, T>::field_name)>> = 1 + field_index<N + 1, T, U>;
|
||||
|
||||
/// @brief Concat multiple tuples in one big tuple
|
||||
/// @tparam ...input_t Multiple std::tuple types to concat
|
||||
template <typename... input_t>
|
||||
using tuple_cat_t = decltype(std::tuple_cat(std::declval<input_t>()...));
|
||||
|
||||
template <typename T, typename Tuple>
|
||||
constexpr bool tuple_contains_type = false;
|
||||
template <typename T, typename... Ts>
|
||||
constexpr bool tuple_contains_type<T, std::tuple<Ts...>> = std::disjunction_v<std::is_same<T, Ts>...>;
|
||||
|
||||
template <typename T, typename Tuple>
|
||||
constexpr int get_tuple_index = 0;
|
||||
template <typename T, typename... Rest>
|
||||
constexpr int get_tuple_index<T, std::tuple<T, Rest...>> = 0;
|
||||
template <typename T, typename First, typename... Rest>
|
||||
constexpr int get_tuple_index<T, std::tuple<First, Rest...>> = 1 + get_tuple_index<T, std::tuple<Rest...>>;
|
||||
|
||||
// Template black magic to loop at compile time
|
||||
template <std::size_t... indices, class LoopBody>
|
||||
void loop_impl(std::index_sequence<indices...>, LoopBody&& loop_body) {
|
||||
(loop_body(std::integral_constant<std::size_t, indices>{}), ...);
|
||||
}
|
||||
|
||||
template <std::size_t N, class LoopBody>
|
||||
void loop(LoopBody&& loop_body) {
|
||||
loop_impl(std::make_index_sequence<N>{}, std::forward<LoopBody>(loop_body));
|
||||
}
|
||||
|
||||
namespace details {
|
||||
template <std::size_t TRem>
|
||||
class TupleForEachHelper {
|
||||
public:
|
||||
template <typename TTuple, typename TFunc>
|
||||
static void exec(TTuple&& tuple, TFunc&& func) {
|
||||
using Tuple = typename std::decay<TTuple>::type;
|
||||
static const std::size_t TupleSize = std::tuple_size<Tuple>::value;
|
||||
static_assert(TRem <= TupleSize, "Incorrect parameters");
|
||||
|
||||
// Invoke function with current element
|
||||
static const std::size_t Idx = TupleSize - TRem;
|
||||
func(std::get<Idx>(std::forward<TTuple>(tuple)));
|
||||
|
||||
// Compile time recursion - invoke function with the remaining elements
|
||||
TupleForEachHelper<TRem - 1>::exec(std::forward<TTuple>(tuple), std::forward<TFunc>(func));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
class TupleForEachHelper<0> {
|
||||
public:
|
||||
// Stop compile time recursion
|
||||
template <typename TTuple, typename TFunc>
|
||||
static void exec(TTuple&& tuple, TFunc&& func) {
|
||||
static_cast<void>(tuple);
|
||||
static_cast<void>(func);
|
||||
}
|
||||
};
|
||||
} // namespace details
|
||||
|
||||
template <typename TTuple, typename TFunc>
|
||||
void tupleForEach(TTuple&& tuple, TFunc&& func) {
|
||||
using Tuple = typename std::decay<TTuple>::type;
|
||||
static const std::size_t TupleSize = std::tuple_size<Tuple>::value;
|
||||
|
||||
details::TupleForEachHelper<TupleSize>::exec(std::forward<TTuple>(tuple), std::forward<TFunc>(func));
|
||||
}
|
||||
|
||||
} // namespace sp
|
||||
Reference in New Issue
Block a user