将向量数据复制到具有不同元素数据类型的元组的最佳做法是什么?
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);
}
为了让它工作有点困难,但这是我为 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());
}
}
我在 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);
}
为了让它工作有点困难,但这是我为 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());
}
}