连接任意数量的 std::arrays,仅使用最少的 ctor 调用

问题描述 投票:0回答:1

我想实现这个函数(一个可以连接任意数量数组的函数,并且它也考虑值类别):

template <typename ELEMENT, std::size_t ...SIZE>
constexpr auto concat(std::array<ELEMENT, SIZE> &&&...arrays) {
    return std::array<ELEMENT, SUMMED_SIZE>{ CONCATENATED_ARRAY_ELEMENTS };
}

备注:

  • &&&
    ,我的意思是
    arrays
    中的每个数组都可以是右值/左值引用(可以混合)
  • 我所说的
    SUMMED_SIZE
    ,是指SIZE的总和(这很简单)
  • 我所说的
    CONCATENATED_ARRAY_ELEMENTS
    ,是指每个
    arrays
    数组的所有元素连接起来。如果
    arrays
    中的数组是右值/左值,则
    CONCATENATED_ARRAY_ELEMENTS
    中对应的元素也应该是右值/左值。
  • 我不想有额外的移动/复制构造函数调用(否则使用递归实现这一点会很简单),我只想为
    arrays
    中的每个元素进行一次移动/复制。
  • ELEMENT
    可能无法默认构造,因此元素必须通过复制/移动构造函数来构造。

这可以吗?

对于两个数组实现这个函数并不难(godbolt),但我不知道如何将其推广到两个以上的数组。我可以手动编写 3/4/5/etc-argument 函数,但所需函数的数量呈指数级增长。

c++ c++26
1个回答
0
投票

您可以使用 C++17 折叠表达式以避免递归解包。

我认为不可能按值类别复制或移动,因为完美转发在这里不适用,因此从函数内部,每个数组将被视为左值引用。

由于右值引用可以绑定到对

const
的左值引用,我建议通过
const std::array<int, Ns> & ...
获取参数,以便能够在调用中混合左值/右值引用作为参数。

这会导致如下所示的结果:

template <typename T, std::size_t ... Ns>
constexpr auto concat(const std::array<T, Ns> & ... arrays)
{
    std::array<T, (Ns + ...)> result;

    auto it = result.begin();
    ([&](){
        std::copy_n(arrays.begin(), Ns, it);
        it += Ns;
    }(), ...);

    return result;
}

当然,您可以仅使用右值引用为特定情况定义重载,以便通过移动替换副本:

template <typename T, std::size_t ... Ns>
constexpr auto concat(std::array<T, Ns> && ... arrays)
{
    std::array<T, (Ns + ...)> result;

    auto it = result.begin();
    ([&](){
        std::copy_n(std::make_move_iterator(arrays.begin()), Ns, it);
        it += Ns;
    }(), ...);

    return result;
}
© www.soinside.com 2019 - 2024. All rights reserved.