如何实现可拼接任意std::array的constexpr函数,最小化构造调用
实现方案
完全可以实现,借助C++17及以上的折叠表达式、std::index_sequence和完美转发特性,无需手动编写多参数版本。以下是符合所有要求的实现:
完整代码
#include <array> #include <utility> #include <tuple> #include <type_traits> namespace detail { // 辅助函数:转发单个数组的所有元素,保留值类别 template <typename Array, std::size_t... Idx> constexpr auto forward_elements(Array&& arr, std::index_sequence<Idx...>) { return std::initializer_list<std::remove_reference_t<typename Array::value_type>>{ std::forward<decltype(arr[Idx])>(arr[Idx])... }; } // 折叠所有数组的元素列表,合并为一个初始化列表 template <typename... Arrays> constexpr auto concat_elements(Arrays&&... arrays) { using ElementType = typename std::remove_reference_t<std::tuple_element_t<0, std::tuple<Arrays...>>>::value_type; return std::initializer_list<ElementType>{ forward_elements(std::forward<Arrays>(arrays), std::make_index_sequence<std::tuple_size_v<std::remove_reference_t<Arrays>>>{}).begin()..., ... }; } } // namespace detail template <typename... Arrays> constexpr auto concat(Arrays&&... arrays) { using ElementType = typename std::remove_reference_t<std::tuple_element_t<0, std::tuple<Arrays...>>>::value_type; constexpr std::size_t TotalSize = (std::tuple_size_v<std::remove_reference_t<Arrays>> + ...); return std::array<ElementType, TotalSize>{ detail::concat_elements(std::forward<Arrays>(arrays)...) }; }
关键特性解释
- 混合引用支持:通过万能引用
Arrays&&...和std::forward实现对左值、右值数组的完美转发,元素的拷贝/移动语义完全匹配原数组。 - 总大小计算:使用C++17折叠表达式
(std::tuple_size_v<...> + ...)直接计算所有数组的大小总和,无需递归逻辑。 - 单次构造保证:每个元素通过
std::forward直接转发到目标数组的初始化列表,仅触发一次拷贝或移动构造,无额外临时对象产生。 - 非默认构造兼容:目标数组通过初始化列表直接构造元素,完全依赖原数组的元素拷贝/移动,不要求
ELEMENT支持默认构造。
验证示例
struct NonDefaultConstructible { int val; constexpr NonDefaultConstructible(int v) : val(v) {} NonDefaultConstructible(const NonDefaultConstructible&) = default; NonDefaultConstructible(NonDefaultConstructible&&) = default; }; constexpr std::array<NonDefaultConstructible, 2> arr1 = {NonDefaultConstructible(1), NonDefaultConstructible(2)}; constexpr std::array<NonDefaultConstructible, 3> arr2 = {NonDefaultConstructible(3), NonDefaultConstructible(4), NonDefaultConstructible(5)}; constexpr auto result = concat(arr1, std::move(arr2)); static_assert(result.size() == 5); static_assert(result[0].val == 1); static_assert(result[4].val == 5);
内容的提问来源于stack exchange,提问作者geza
相关产品推荐
相关产品推荐

