将向量数据复制到具有不同元素数据类型的元组的最佳做法是什么?

What is a good practice to copy vector data to a tuple with different element data type?

我在 C++11 中使用 GCC 4.8.3。

我有一个 std::vector<uint8_t>,我需要将其内容复制到一个 std::tuple。 元组元素描述了向量的数据结构。 Exp.: std::tuple<uint32_t,uint16_t> 将对应于一个 6 字节的向量,其中前四个字节属于 uint32_t,后两个字节属于 uint16_t.

这是不可更改的要求,因为它是更大模板的一部分 class 但为了简化我的问题而进行了分解。

编辑:字节顺序保证正确。 谢谢 WhozCraig

我现在有两个变体

template<typename T, int TupleIndex, unsigned int BufferPosition>
void extractBufferToTuple(T&& tuple, std::vector<uint8_t>&buffer) {
    std::get<TupleIndex>(tuple) = *(typename std::tuple_element<TupleIndex,T>::type*)&buffer[BufferPosition];
}

template<typename T, int TupleIndex, unsigned int BufferPosition>
void extractBufferToTuple(T&& tuple, std::vector<uint8_t>&buffer) {
    std::copy(&buffer[BufferPosition], &buffer[BufferPosition] + sizeof(typename std::tuple_element<TupleIndex,T>::type), (uint8_t*)&std::get<TupleIndex>(tuple));
}

调用它看起来像这样

std::tuple<uint32_t,uint32_t> myTuple;
std::vector<uint8_t> buffer;
buffer.resize(6);
uint32_t value0 = 123;
uint16_t value1 = 456;
std::copy((uint8_t*)&value0,(uint8_t*)&value0+sizeof(value0),&buffer[0]);
std::copy((uint8_t*)&value1,(uint8_t*)&value1+sizeof(value1),&buffer[sizeof(value0)]);


extractBufferToTuple<decltype(myTuple),0,0>(std::forward<decltype(testClass)::Tuple>(myTuple),buffer);        
extractBufferToTuple<decltype(myTuple),1,sizeof(std::tuple_element<0,decltype(myTuple)>::type)>(std::forward<decltype(myTuple)>(myTuple),buffer);    

是否有一种有效且安全的方法,或者是否有更好的做法没有任何可能的陷阱?

大概是这样的:

template <typename T>
size_t extractBuffer(const std::vector<uint8_t>& buffer, size_t start_index, T* to) {
  std::memcpy(to, &buffer[start_index], sizeof(*to));
  return start_index + sizeof(*to);
}

template <typename ... Ts>
size_t extractBuffer(const std::vector<uint8_t>& buffer, size_t start_index,
                     std::tuple<Ts...>* to) {
  auto extractHelper = [&](auto& ... elems) {
    auto _ = {(start_index = extractBuffer(buffer, start_index, &elems)) ...};
    return start_index;
  };
  return std::apply(extractHelper, *to);
}

Demo

为了让它工作有点困难,但这是我为 C++11 想出的。它不像 Igor

那样圆滑
template<size_t TupleIndex>
struct ExtractBufferToTuple {
    template<typename T, typename Iterator>
    static inline void extractBufferToTuple(T& tuple, Iterator bufferPosition) {
        auto nextBufferPosition = bufferPosition - sizeof (typename ::std::tuple_element<TupleIndex, T>::type);
        std::copy(nextBufferPosition, bufferPosition, (uint8_t*) & ::std::get<TupleIndex>(tuple));
        ExtractBufferToTuple < TupleIndex - 1 > ::extractBufferToTuple(tuple, nextBufferPosition);
    }
};

template<>
struct ExtractBufferToTuple<0> {
    template<typename T, typename Iterator>
    static inline void extractBufferToTuple(T& tuple, Iterator bufferPosition) {
        auto nextBufferPosition = bufferPosition - sizeof (typename ::std::tuple_element<0, T>::type);
        std::copy(nextBufferPosition, bufferPosition, (uint8_t*) & ::std::get<0>(tuple));
    }
};

template<typename T, typename ... TArgs>
void extractBufferToTuple(T& tuple,const std::vector<uint8_t>&buffer) {
    size_t tupleByteSize = byteSize < TArgs...>();
    if (buffer.size() == tupleByteSize) {
        ExtractBufferToTuple<::std::tuple_size<typename ::std::decay<T>::type>::value - 1 > ::extractBufferToTuple(tuple, buffer.end());
    }
}