summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohannes Stoelp <johannes.stoelp@gmail.com>2024-10-04 21:13:49 +0200
committerJohannes Stoelp <johannes.stoelp@gmail.com>2024-10-04 21:13:49 +0200
commita41d3104dc730d2cba15e1ef290b52e032d6e054 (patch)
tree94d365e44b6d01255ddfbbf2d9c67c29fdb0ae1d
parentba4e23cd9e1e115591c877a144098fc61741bc2a (diff)
downloadcpp-templates-a41d3104dc730d2cba15e1ef290b52e032d6e054.tar.gz
cpp-templates-a41d3104dc730d2cba15e1ef290b52e032d6e054.zip
variadic: mapping from generic types to common type
-rw-r--r--variadic_to_common_type.cc132
1 files changed, 132 insertions, 0 deletions
diff --git a/variadic_to_common_type.cc b/variadic_to_common_type.cc
new file mode 100644
index 0000000..d8609b5
--- /dev/null
+++ b/variadic_to_common_type.cc
@@ -0,0 +1,132 @@
+#if 0
+set -xe
+trap 'rm -f a.out' EXIT
+g++ -std=c++17 -Wall -Wextra -fsanitize=address -fsanitize=undefined variadic_to_common_type.cc && ./a.out | c++filt -t
+clang++ -std=c++17 -Wall -Wextra -fsanitize=address -fsanitize=undefined variadic_to_common_type.cc && ./a.out | c++filt -t
+
+g++ -std=c++17 -Wall -Wextra variadic_to_common_type.cc && ./a.out | c++filt -t
+which valgrind && valgrind ./a.out
+exit 0
+#endif
+
+#include <array>
+#include <type_traits>
+
+#include <cstddef>
+#include <cstdint>
+
+// Variadic template arguments to common type.
+//
+// This shows a method how to map variadic template arguments to a common type
+// which can be used further down the processing pipeline.
+
+struct bytes {
+ const uint8_t* ptr;
+ size_t len;
+};
+
+// -- TO_BYTES CONVERTER -------------------------------------------------------
+
+template <typename T>
+constexpr bytes to_bytes(const T& val) {
+ static_assert(std::is_arithmetic_v<T>, "");
+ return {.ptr = reinterpret_cast<const uint8_t*>(&val), .len = sizeof(val)};
+}
+
+template <typename T, size_t N>
+constexpr bytes to_bytes(const T (&vals)[N]) {
+ static_assert(std::is_arithmetic_v<T>, "");
+ static_assert(sizeof(vals) == sizeof(T) * N, "");
+ return {.ptr = &vals, .len = sizeof(vals)};
+}
+
+template <typename T, size_t N>
+constexpr bytes to_bytes(const std::array<T, N>& vals) {
+ static_assert(std::is_arithmetic_v<T>, "");
+ return {.ptr = reinterpret_cast<const uint8_t*>(vals.data()),
+ .len = sizeof(T) * N};
+}
+
+// -- SCALAR GENERATOR & ALIAS -------------------------------------------------
+
+// Utility to generate scalar values of a specific type.
+
+template <typename T>
+struct scalar {
+ static_assert(std::is_arithmetic_v<T>, "");
+
+ template <typename F>
+ constexpr T operator()(F val) const {
+ static_assert(std::is_convertible_v<F, T>, "");
+ return static_cast<T>(val);
+ }
+};
+
+inline constexpr scalar<uint64_t> u64;
+inline constexpr scalar<double> f64;
+
+// -- ARRAY GENERATOR & ALIAS --------------------------------------------------
+
+// Utility to generate array values of a specific type.
+
+template <typename T>
+struct array {
+ static_assert(std::is_arithmetic_v<T>, "");
+
+ template <typename... F>
+ constexpr std::array<T, sizeof...(F)> operator()(F... val) const {
+ static_assert(is_convertible<F...>(), "");
+ return {static_cast<T>(val)...};
+ }
+
+ // Conversion checker helper.
+
+ template <typename F>
+ static constexpr bool is_convertible() {
+ return std::is_convertible_v<F, T>;
+ }
+
+ template <typename F1, typename F2, typename... Fs>
+ static constexpr bool is_convertible() {
+ return std::is_convertible_v<F1, T> && is_convertible<F2, Fs...>();
+ }
+};
+
+inline constexpr array<uint64_t> u64v;
+inline constexpr array<double> f64v;
+
+// -- SERIALIZER ---------------------------------------------------------------
+
+// Example consumer of variadic arguments which are mapped to the common `bytes`
+// type.
+
+#include <cstdio>
+
+#include <initializer_list>
+#include <typeinfo>
+
+template <typename... Args>
+void serialize(Args&&... args) {
+ // auto vals = {to_bytes(args)...};
+ std::initializer_list<bytes> vals = {to_bytes(args)...};
+
+ for (auto b : vals) {
+ std::printf("bytes: .ptr=%p .len=%zu -> first by %u\n", b.ptr, b.len,
+ *b.ptr);
+ }
+
+ auto vals_with_type = {
+ std::pair<bytes, const char*>{to_bytes(args), typeid(args).name()}...};
+ for (auto p : vals_with_type) {
+ auto b = p.first;
+ auto n = p.second;
+ // Pipe to `c++filt -t` to also interpret type mangling.
+ std::printf("bytes: .ptr=%p .len=%zu -> type=%s\n", b.ptr, b.len, n);
+ }
+}
+
+// -- TEST ME ------------------------------------------------------------------
+
+int main() {
+ serialize(u64(1), f64(2), u64v(10, 11, 12, 13), f64v(20.0, 21.0, 22.0));
+}