You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将集合参数包展平为成员初始化的std::array?

实现支持嵌套初始化的自定义group类(保留std::array与constexpr特性)

问题描述

需要实现自定义group类的嵌套初始化能力:

group a{1, 2};
group b{a, 3}; // 期望等价于 group b{1, 2, 3}

现有基础代码仅支持普通参数初始化,尝试嵌套初始化时触发编译错误:array must be initialized with a brace-enclosed initializer,调整初始化语法后仍无法解决,且要求必须保留std::array存储和constexpr特性。

解决方案

基于C++20 Concepts实现通用的集合展平工具,编写make_collection和make_array函数,不仅支持std::array,还能适配模板签名类似std::array的自定义结构(如group类),自动将嵌套的集合参数展平为一维参数包,完成初始化。

核心展平工具代码

#include <type_traits>
#include <concepts>
#include <cstdint>
#include <tuple>
#include <array>

using std::size_t;

struct array_marker {};

template <typename T>
concept IsTupleLike = requires { std::tuple_size<typename std::remove_cvref<T>::type>::value; };

template <typename T>
concept IsArrayMarker = std::same_as<std::remove_cvref_t<T>, array_marker>;

template <typename T>
concept IsPlain = !IsArrayMarker<T> && !IsTupleLike<T>;

template <typename... Ts>
struct tuple_data {
        static constexpr size_t size = (tuple_data<Ts>::size + ...);
        using value_type = std::common_type_t<typename tuple_data<Ts>::value_type...>;
};

template <typename T>
struct tuple_data<T> {
        static constexpr size_t size = 1;
        using value_type = std::remove_cvref_t<T>;
};

template <IsTupleLike T>
struct tuple_data<T> {
        static constexpr size_t size = std::tuple_size_v<std::remove_cvref_t<T>>;
        using value_type = std::remove_cvref_t<T>::value_type;
};

template <typename Ret, IsPlain Arg, typename... Args>
constexpr inline Ret make_collection(Arg &&arg, Args &&... args) {
        return make_collection<Ret>(std::forward<Args>(args)..., std::forward<Arg>(arg));
}

template <typename Ret, IsTupleLike Tup, typename... Args, size_t... Indices>
constexpr inline Ret make_collection(std::index_sequence<Indices...> &&, Tup &&arr, Args &&... args) {
        return make_collection<Ret>(std::forward<Args>(args)..., get<Indices>(arr)...);
}

// 匹配所有std::array或类似的tuple-like类型
template <typename Ret, IsTupleLike Tup, typename... Args>
constexpr inline Ret make_collection(Tup &&arr, Args &&... args) {
        return make_collection<Ret>(std::make_index_sequence<tuple_data<Tup>::size>{}, std::forward<Tup>(arr), std::forward<Args>(args)...);
}

template <typename Ret, typename... Args>
constexpr inline Ret make_collection(IsArrayMarker auto &&, Args &&... args) {
        return { args... };
}

template <template <typename, size_t> typename ArrayLike = std::array,
        typename... Args,
        typename Ret = ArrayLike<typename tuple_data<Args...>::value_type, tuple_data<Args...>::size>>
constexpr inline Ret make_array(Args &&... args) {
        return make_collection<Ret>(std::forward<Args>(args)..., array_marker{});
}

自定义group类实现

#include <array>
#include <iostream>

template <typename Member, size_t Size>
struct group {
    using value_type = Member;

    constexpr group() : arr{} {}
    
    // 利用make_array自动展平嵌套参数
    constexpr group(auto &&... args) : arr(make_array(args...)) {}

    std::array<Member, Size> arr;
};

// 推导指引:自动推导group的元素类型和大小
group(auto &&... args) -> group<typename tuple_data<decltype(args)...>::value_type, tuple_data<decltype(args)...>::size>;

// 特化tuple_size,让group满足IsTupleLike概念
template <typename Member, size_t Size>
struct std::tuple_size<group<Member, Size>> : std::integral_constant<std::size_t, Size> {};

// 实现get接口,支持tuple-like操作
template <size_t Index, typename T, size_t Size>
T &get(group<T, Size> &g) {
    return g.arr[Index];
}

template <size_t Index, typename T, size_t Size>
const T &get(const group<T, Size> &g) {
    return g.arr[Index];
}

// 重载输出运算符,方便打印测试
template <size_t Index = 0>
static inline std::ostream &operator<<(std::ostream &os, IsTupleLike auto &&tup) {
    constexpr const size_t size = std::tuple_size_v<std::remove_cvref_t<decltype(tup)>>;
    if constexpr (Index == 0) {
        return operator<<<Index + 1>(os << "{", tup) << "}";
    } else if constexpr (Index > size) {
        return os;
    } else if constexpr (Index == 1) {
        return operator<<<2>(os << get<0>(tup), tup);
    } else {
        return operator<<<Index + 1>(os << ", " << get<Index - 1>(tup), tup);
    }
}

// 打印工具函数
static inline void println(auto &&... args) {
    ((std::cout << args << " "), ...) << "\n";
}

int main() {
    auto g1 = make_array<group>(1, 2, 3);
    auto g2 = make_array<group>(g1, 4, 5, 6);
    group g3{g1, 0, g2};
    println(g1, g2, g3);
}

测试输出

{1, 2, 3} {1, 2, 3, 4, 5, 6} {1, 2, 3, 0, 1, 2, 3, 4, 5, 6}

内容的提问来源于stack exchange,提问作者boat d

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 20:50:55