Home > database >  C template function to concatenate both std::vector and std::array types
C template function to concatenate both std::vector and std::array types

Time:01-31

I have project where I am working with both fixed and variable length arrays of bytes. I want to have a function that can concatenate two arbitrary containers of bytes and return a single vector. Currently I am using

std::vector<uint8_t> catBytes(uint8_t const* bytes1, size_t const len1, 
                              uint8_t const* bytes2, size_t const len2) {
    std::vector<uint8_t> all_bytes;
    all_bytes.reserve(len1   len2);
    all_bytes.insert(all_bytes.begin(), bytes1, bytes1   len1);
    all_bytes.insert(all_bytes.begin()   len1, bytes2, bytes2   len2);
    return all_bytes;
} // catBytes

However, I would like more generic way to do this, which better uses the capabilities of C . I do not want to just accept iterators. I am trying to figure out how to accept two arbitrary containers and return a vector containing their contents. Ideally I would also not like to have to know the type inside the vector.

Something like

std::vector<unit_8> v1 = { 1, 2, 3, 4 };
std::array<unit_8, 4> a1 = { 1, 2, 3, 4 };
std::array<unit_8, 2> a2 = { 1, 2 };
auto res1 = concat(v1, a1); // std::vector<uint_8> of size 8
auto res2 = concat(a1, a2); // std::vector<uint_8> of size 6

// or

std::vector<char> v2 = { 1, 2, 3, 4 };
std::array<char, 4> a3 = { 1, 2, 3, 4 };
auto res3 = concat(v1, a1); // std::vector<char> of size 8

I think there is a templated approach to this but I just have not been able to figure it out.

CodePudding user response:

std::array, std::vector and other contiguous_ranges can be converted to a lightweight std::span, which you can use for type erasure.

#include <cstdint>
#include <span>
#include <vector>

std::vector<uint8_t> 
catBytes(std::span<const uint8_t> x, std::span<const uint8_t> y) {
  std::vector<uint8_t> all_bytes;
  all_bytes.reserve(x.size()   y.size());
  all_bytes.insert(all_bytes.begin(), x.begin(), x.end());
  all_bytes.insert(all_bytes.end(), y.begin(), y.end());
  return all_bytes;
}

Demo

CodePudding user response:

In general, generic arbitrary, means templates.

Something like this?

template<class SizedRange1, class SizedRange2>
auto concat(SizedRange1 const& r1, SizedRange2 const& r2) {
    std::vector<typename SizedRange1::value_type> ret;
    ret.reserve(r1.size()   r2.size());

    using std::begin; using std::end;
    ret.insert(ret.end(), begin(r1), end(r1));
    ret.insert(ret.end(), begin(r2), end(r2));

    return ret;
}
  •  Tags:  
  • Related