连接 std::vector 和 std::array 类型的 C++ 模板函数

C++ template function to concatenate both std::vector and std::array types

我有一个项目,我正在使用固定和可变长度的字节数组。我想要一个可以连接两个任意字节容器和 return 单个向量的函数。目前我正在使用

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

但是,我想要更通用的方法来执行此操作,从而更好地利用 C++ 的功能。我不想只接受迭代器。我想弄清楚如何接受两个任意容器和 return 一个包含其内容的向量。理想情况下,我也不想知道向量中的类型。

类似

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

我认为有一个模板化的方法来解决这个问题,但我还没有弄明白。

一般来说,generic + arbitrary,就是模板。

是这样的吗?

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;
}

编辑:

@康桐薇解决方案的优点(假设您只对连接连续的内存容器感兴趣,如您所说)是您有一个 单个 函数并且您避免了代码膨胀。

正如您在评论中注意到的那样,问题是您无法推断出元素类型,原则上元素类型可以是任何类型,因此无论如何您又回到了需要模板的状态。

幸运的是,如果您有许多不同的输入容器,这是组合的,您可以结合这两种方法并减少生成为机器代码的函数数量。

template<class T>
std::vector<T> 
concat_aux(std::span<const T> x, std::span<const T> y) {
  std::vector<T> ret;
  ret.reserve(x.size() + y.size());
  ret.insert(ret.end(), x.begin(), x.end());
  ret.insert(ret.end(), y.begin(), y.end());
  return ret;
}

template<class ContinuousRange1, class ContinuousRange2>
auto concat(ContinuousRange1 const& r1, ContinuousRange2 const& r2) {
  return concat_aux<typename ContinousRange1::value_type>(r1, r2);
}

这里的优势很小,但是如果函数 concat 非常复杂,最后一种方法会奏效,因为它只会为不同类型的元素生成代码,而不是为您的容器平方数生成代码实例化代码。

std::arraystd::vectorcontiguous_ranges可以转换为轻量级的std::span,可用于类型擦除。

#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