首页 > 解决方案 > C++ 可变参数模板打包到 std::array 并解包

问题描述

我想将变量打包在一个数组中,然后使用这样的接口解包

int x; float y; double z;
auto data = PackArray(x, y, z); // serializes without padding

...

int x; float y; double z;
UnpackArray(data, x, y, z); // copies data from the array to x, y, z

我试过

template<class... T>
constexpr size_t SumOfSizeofs(const T&...)
{
    return (sizeof(T) + ...);
}

// Creates array of u8 with size = sum(sizeofs)
template <class A, class ...Rest>
auto PackArray(A& a, Rest&... rest)
{
    return std::array<u8, SumOfSizeofs(a, rest...)>; // doesn't work
}

template <class Array, class...Rest>
auto UnpackArray(Array& array, Rest&... rest)
{
    // iterates through sizeof each element, copying to its new buffer from the array
}

如果有一个std::packed_tuple它会很棒...... :(我对模板语法不好,帮助?

标签: c++templates

解决方案


这是我的尝试:

#include <array>
#include <cstddef>
#include <cstdio>
#include <cstring>
#include <memory>
#include <type_traits>

template <class... T>
[[nodiscard]] auto PackArray(T&&... args) {
  static_assert(
      (std::is_trivially_copyable_v<std::remove_reference_t<T>> && ...),
      "Packing requires trivial-copying");
  std::array<std::byte, (sizeof(T) + ... + 0)> data;
  std::size_t offet = 0;
  (std::memcpy(data.data() + (offet += sizeof(args)) - sizeof(args),
               std::addressof(args), sizeof(args)), ...);
  return data;
}

template <std::size_t sz, class... T>
auto UnpackArray(std::array<std::byte, sz> const& data, T&... args) {
  static_assert(sz == (sizeof(T) + ... + 0), "Mismatch");
  static_assert(
      (std::is_trivially_copyable_v<std::remove_reference_t<T>> && ...),
      "UnPacking requires trivial-copying");
  std::size_t offet = 0;
  (std::memcpy(std::addressof(args),
               data.data() + (offet += sizeof(args)) - sizeof(args),
               sizeof(args)), ...);
}

int main() {
  int x = 42;
  float y = 3.14f;
  double z = 2.72;
  auto data = PackArray(x, y, z);  // serializes without padding

  int x1;
  float y1;
  double z1;
  UnpackArray(data, x1, y1, z1);

  std::printf("%d, %.2f, %.2f", x1, y1, z1);
}

注意使用std::addressof以避免对象重载的问题operator&


推荐阅读