0

I need to convert a tuple to a byte array. This is the code I use to convert to byte array:

    template< typename T > std::array< byte, sizeof(T) >  get_bytes( const T& multiKeys )
    {
     std::array< byte, sizeof(T) > byteArr ;
     const byte* start = reinterpret_cast< const byte* >(std::addressof(multiKeys) ) ;
     const byte* end = start + sizeof(T);
     std::copy(start, end, std::begin(byteArr));
     return byteArr;
    }    

Here is how I call it:

    void foo(T... keyTypes){
        keys = std::tuple<T... >(keyTypes...);
        const auto bytes = get_bytes(keys);
    }

I need to augment this code such that when a pointer is a part of the tuple, I dereference it to it's value and then pass the new tuple, without any pointers, to the get_bytes() function. How do I detect the presence of a pointer in the tuple? I can then iterate through the tuple and dereference it with:

    std::cout << *std::get<2>(keys) << std::endl;
jok
  • 263
  • 2
  • 6

2 Answers2

0

Add a trivial overload: T get_bytes(T const* t) { return getBytes(*t); }.

MSalters
  • 173,980
  • 10
  • 155
  • 350
  • I think this works only if all of the tuple elements are pointers. What if a single tuple element is a char* and the rest are int. – jok Jan 22 '17 at 22:18
  • @jok: Then you call `char get_bytes(char const*)` for the pointer, and `int get_bytes(int)` for the integers. Just to clarify: This of course assumes that you're looping over all tuple elements and calling `get_bytes` on each individual element. – MSalters Jan 23 '17 at 15:17
0

That would be easy with C++14 :

#include <iostream>
#include <tuple>
#include <utility>

template <class T> decltype(auto) get_dereferenced_value(T &&value) {
  return std::forward<T>(value);
}

template <class T> decltype(auto) get_dereferenced_value(T *value) {
  return *value;
}

template <class Tuple, class Indexes> struct get_dereferenced_tuple_impl;

template <class... Args, size_t... Index>
struct get_dereferenced_tuple_impl<std::tuple<Args...>,
                                   std::integer_sequence<size_t, Index...>> {
  decltype(auto) operator()(std::tuple<Args...> const &originalTuple) {
    return std::make_tuple(
        get_dereferenced_value(std::get<Index>(originalTuple))...);
  }
};

template <class Tuple>
decltype(auto) get_dereferenced_tuple(Tuple const &tupleValue) {
  return get_dereferenced_tuple_impl<
      Tuple,
      std::make_integer_sequence<size_t, std::tuple_size<Tuple>::value>>{}(
      tupleValue);
}

int main() {
  char c = 'i';
  std::tuple<char, char *> t{'h', &c};
  auto t2 = get_dereferenced_tuple(t);
  std::cout << std::get<0>(t2) << std::get<1>(t2) << "\n";
  return 0;
}

If you cannot use C++14, then you would have to write more verbose decltype expressions, as well as include an implementation of std::(make_)integer_sequence.

This has a drawback though : copies will be made before copying the bytes. A tuple of references is not a good idea. The most performant version would be a get_bytes able to serialize the entire mixed tuple directly.

Community
  • 1
  • 1
Jean-Bernard Jansen
  • 7,544
  • 2
  • 20
  • 17