#c #vector #copy #tuples
#c #вектор #Копировать #Кортежи
Вопрос:
Я использую GCC 4.8.3 с C 11.
У меня есть a std::vector<uint8_t>
, и мне нужно скопировать его содержимое в a std::tuple
. Элементы кортежа описывают структуру данных вектора. Пример.: std::tuple<uint32_t,uint16_t>
будет соответствовать вектору из 6 байт, где первые четыре байта принадлежат uint32_t
, а вторые два байта uint16_t
.
Это требование не подлежит изменению, поскольку оно является частью более крупного шаблонного класса, но разбито для упрощения моего вопроса.
Редактировать: конечность гарантируется правильной. Спасибо WhozCraig
Сейчас у меня есть два варианта
template<typename T, int TupleIndex, unsigned int BufferPosition>
void extractBufferToTuple(Tamp;amp; tuple, std::vector<uint8_t>amp;buffer) {
std::get<TupleIndex>(tuple) = *(typename std::tuple_element<TupleIndex,T>::type*)amp;buffer[BufferPosition];
}
и
template<typename T, int TupleIndex, unsigned int BufferPosition>
void extractBufferToTuple(Tamp;amp; tuple, std::vector<uint8_t>amp;buffer) {
std::copy(amp;buffer[BufferPosition], amp;buffer[BufferPosition] sizeof(typename std::tuple_element<TupleIndex,T>::type), (uint8_t*)amp;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*)amp;value0,(uint8_t*)amp;value0 sizeof(value0),amp;buffer[0]);
std::copy((uint8_t*)amp;value1,(uint8_t*)amp;value1 sizeof(value1),amp;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);
Является ли один из них допустимым и безопасным подходом или есть какая-то лучшая практика без каких-либо возможных ошибок?
Комментарии:
1. Игнорирование очевидной разбивки, когда исходное и целевое конечное представление несовместимы?
2. Спасибо, что указали на это. Это также гарантировано.
3. Примечание к подписи: ссылка на значение rvalue для параметра out кажется сомнительной. Если кто-то передает временный, то вывод не может быть использован. Это только усложняет реализацию почти без очевидной выгоды. Кроме того, источники, доступные только для чтения, должны передаваться по ссылке на const . (Передача неконстантной ссылки lvalue сообщает вызывающим: «Я могу изменить этот объект».)
4. Это очень хорошие подсказки. Не думал об этом, но имеет смысл.
Ответ №1:
Возможно, что-то в этом роде:
template <typename T>
size_t extractBuffer(const std::vector<uint8_t>amp; buffer, size_t start_index, T* to) {
std::memcpy(to, amp;buffer[start_index], sizeof(*to));
return start_index sizeof(*to);
}
template <typename ... Ts>
size_t extractBuffer(const std::vector<uint8_t>amp; buffer, size_t start_index,
std::tuple<Ts...>* to) {
auto extractHelper = [amp;](autoamp; ... elems) {
auto _ = {(start_index = extractBuffer(buffer, start_index, amp;elems)) ...};
return start_index;
};
return std::apply(extractHelper, *to);
}
Комментарии:
1. Я думаю, мы могли бы переписать std::apply, чтобы я мог использовать его в C 11?
2.
std::apply
может быть заменен чуть более подробным подходом , основанным наstd::index_sequence
. Последнее является функцией C 14, но тривиально использовать свою собственную в C 11, намного проще, чемstd::apply
. Вы должны быть в состоянии найти его.3. Большое вам спасибо. Я постараюсь реализовать это на C 11. Но ваш подход выглядит очень красиво.
4. Была ли какая-либо мысль об использовании memcpy вместо copy в данном конкретном случае? Просто интересно
5.
static_cast<void>(_);
также может быть полезно для автоматического предупреждения о неиспользуемой переменной.
Ответ №2:
Было немного сложно заставить его работать, но это то, что я придумал для C 11. Это не так гладко, как Игорь
template<size_t TupleIndex>
struct ExtractBufferToTuple {
template<typename T, typename Iterator>
static inline void extractBufferToTuple(Tamp; tuple, Iterator bufferPosition) {
auto nextBufferPosition = bufferPosition - sizeof (typename ::std::tuple_element<TupleIndex, T>::type);
std::copy(nextBufferPosition, bufferPosition, (uint8_t*) amp; ::std::get<TupleIndex>(tuple));
ExtractBufferToTuple < TupleIndex - 1 > ::extractBufferToTuple(tuple, nextBufferPosition);
}
};
template<>
struct ExtractBufferToTuple<0> {
template<typename T, typename Iterator>
static inline void extractBufferToTuple(Tamp; tuple, Iterator bufferPosition) {
auto nextBufferPosition = bufferPosition - sizeof (typename ::std::tuple_element<0, T>::type);
std::copy(nextBufferPosition, bufferPosition, (uint8_t*) amp; ::std::get<0>(tuple));
}
};
template<typename T, typename ... TArgs>
void extractBufferToTuple(Tamp; tuple,const std::vector<uint8_t>amp;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());
}
}