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

如何结合指定对象与std::array元素生成PinBox可变参数初始化列表?

问题描述

假设有两种引脚类型BoardPin和SpecialPin,以及持有BoardPin的Board类:

// Pin for Board
struct BoardPin { };

// another kind of pin
struct SpecialPin { };

// a Board that comes with a Pin
class Board
{
    // Board's pin
    BoardPin m_pin;

public:
    // get the Board's pin
    constexpr BoardPin &get_pin()
    {
        return m_pin;
    }
};

同时有一个可容纳任意类型引脚的可变参数容器PinBox:

// a box of pins of any kind
template <typename... PinTypes>
class PinBox
{
    std::tuple<PinTypes...> m_pins;

public:
    // construct a PinBox with any kinds of pins
    explicit PinBox(PinTypes &...pins) : m_pins{std::tie(pins...)} {};
};

最后是包含多个Board和一个SpecialPin的BoardRoom类:

// a BoardRoom has several Boards
// and a SpecialPin
class BoardRoom
{
    // number of boards a room has
    static constexpr size_t M_NUM_BOARDS = 4;

    // the BoardRoom's Boards
    std::array<Board, M_NUM_BOARDS> m_boards;

    // the BoardRoom's SpecialPin
    SpecialPin m_special_pin;

    // get the SpecialPin
    constexpr SpecialPin& get_special_pin() {
        return m_special_pin;
    }

public:
    // do something that require a PinBox of all the pins
    void do_something();
};

当前需要实现BoardRoom::do_something(),构造包含get_special_pin()返回值和所有m_boards中Board的pin的PinBox,要求无需手动逐个枚举std::array元素,且M_NUM_BOARDS变更时无需修改PinBox的定义。

(注:实际场景中,引脚对应互斥锁,Board对应数据库对象,PinBox对应std::scoped_lock,BoardRoom对应需保证一致性的服务器对象)

解决方案

可以利用C++编译时索引序列(std::index_sequence)自动展开std::array元素,生成所有引脚的参数包,再传递给PinBox构造函数,完全避免手动枚举。

实现方式(C++14及以上)

在BoardRoom类中添加私有辅助函数,结合索引序列展开所有Board的引脚,再与特殊引脚组合:

class BoardRoom
{
    // ... 原有成员保持不变 ...

private:
    // 编译时展开array中所有Board的pin,结合特殊引脚生成元组
    template <size_t... Idx>
    auto make_all_pins(std::index_sequence<Idx...>)
    {
        return std::forward_as_tuple(get_special_pin(), m_boards[Idx].get_pin()...);
    }

public:
    void do_something();
};

// 实现do_something
void BoardRoom::do_something()
{
    // 生成对应长度的索引序列,调用辅助函数获取所有引脚引用
    auto all_pins = make_all_pins(std::make_index_sequence<M_NUM_BOARDS>{});
    // 用std::apply把元组展开为PinBox的构造参数
    PinBox box = std::apply([](auto&... pins) { return PinBox(pins...); }, all_pins);

    // 后续业务逻辑...
}

简化版本(C++17及以上)

借助C++17的模板lambda和折叠表达式,可以省去单独的辅助函数,直接在do_something内完成逻辑:

void BoardRoom::do_something()
{
    auto build_pin_box = [this]<size_t... Idx>(std::index_sequence<Idx...>) {
        return PinBox(get_special_pin(), m_boards[Idx].get_pin()...);
    };

    PinBox box = build_pin_box(std::make_index_sequence<M_NUM_BOARDS>{});

    // 后续业务逻辑...
}

核心说明

  • std::make_index_sequence<M_NUM_BOARDS>会在编译时生成0,1,...,M_NUM_BOARDS-1的索引序列,自动匹配std::array的所有元素位置。
  • 无论M_NUM_BOARDS修改为任何值,代码都无需手动调整枚举逻辑,完全由编译时自动处理。
  • 最终生成的PinBox包含SpecialPin和所有BoardPin的引用,效果与手动枚举完全一致。

内容的提问来源于stack exchange,提问作者Kingsley Oyelabi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 22:53:20