【问题标题】:concatenation of multiple std::array objects using variadic templates使用可变参数模板连接多个 std::array 对象
【发布时间】:2021-02-22 13:37:48
【问题描述】:

我需要一个实现以下功能的函数:

template<typename T, std::size_t SIZE_L, std::size_t ...SIZE_R>
std::array<T, SIZE_L> concat(const std::array<T, SIZE_R...>&);

这应该将 RHS 上所有传递的数组连接成一个数组。 SIZE_R 的总和应该与 SIZE_L 相同——如果可能的话,不需要手动指定 SIZE_L。

此数组的元素类型将始终为 double。

【问题讨论】:

  • 你可以使用auto作为返回类型吗?
  • SIZE_L -> (... + SIZE_R) (C++17)
  • T 默认可构造吗?
  • 但是你可以这样做:std::array&lt;NonDefaultConstructible, 2&gt; arr{{ NonDefaultConstructible(42), NonDefaultConstructible(51) }};...
  • @Jarod42 -- 抱歉 -- 它是默认可构造的!

标签: c++ variadic


【解决方案1】:

使用默认可构造T,您可能会这样做 (C++17):

template<typename T, std::size_t ...Ns>
std::array<T, (... + Ns)> concat(const std::array<T, Ns>&... arrs)
{
    std::array<T, (... + Ns)> res;
    std::size_t offset = 0;
    
    ((std::copy(arrs.begin(), arrs.end(), res.begin() + offset),
      offset += arrs.size()),
     ...);
    return res;
}

Demo

【讨论】:

  • @FrankPuck:连接需要一些副本...(不过我的版本做了额外的默认构造)。
  • range-v3 有一个 concat 视图,但是结果将不再是连续的。
【解决方案2】:

如果需要,这里有一个版本可以处理无法默认构造的类型 (try it online):

#include <array>
#include <type_traits>
#include <utility>
#include <tuple>

namespace array_concat_helper {

template <std::size_t Idx, typename SizeSeq, typename Enable=void>
struct indices
{
    static constexpr std::size_t tuple_index = 0;
    static constexpr std::size_t elem_index = Idx;
};

template <std::size_t Idx, std::size_t FirstN, std::size_t ...Ns>
struct indices<Idx, std::index_sequence<FirstN, Ns...>,
    std::enable_if_t<(Idx >= FirstN)>>
{
    static constexpr std::size_t tuple_index =
    1 + indices<Idx-FirstN, std::index_sequence<Ns...>>::tuple_index;
    static constexpr std::size_t elem_index =
    indices<Idx-FirstN, std::index_sequence<Ns...>>::elem_index;
};

template <typename T, std::size_t ...Ns, std::size_t ...Is>
std::array<T, (... + Ns)> concat(
    std::index_sequence<Is...>,
    const std::array<T, Ns>&... arrs)
{
    auto arr_tuple = std::tie(arrs...);
    return {{
        std::get<indices<Is, std::index_sequence<Ns...>>::tuple_index>
        (arr_tuple)
        [indices<Is, std::index_sequence<Ns...>>::elem_index]...
    }};
}

} // end namespace array_concat_helper

template<typename T, std::size_t ...Ns>
std::array<T, (... + Ns)> concat(const std::array<T, Ns>&... arrs)
{
    return array_concat_helper::concat(
        std::make_index_sequence<(... + Ns)>{}, arrs...);
}

【讨论】:

  • 很好,它也可以煮咖啡和使用可移动资源吗?
  • @Surt 不是这个版本。但是嗯,如果我们将数组作为转发引用并只使用typename C::value_typestd::tuple_size,那么我们可以混合和匹配左值和右值数组并完美转发......
  • 对处理没有默认可构造类型引起的复杂性感到遗憾:-/
猜你喜欢
  • 2023-03-10
  • 1970-01-01
  • 2015-05-19
  • 2020-02-24
  • 1970-01-01
  • 2013-05-25
  • 2018-03-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多