如何从 std::array 为可变参数构造函数生成初始值设定项列表

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

作为简化,假设我们有两种不同类型的引脚和一个固定其中一种的电路板

// 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;
    }
};

我们需要一个可变的引脚盒,可以容纳任意引脚:

// 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...)} {};
};

最后,这个房间包含所有东西,所有活动都在其中进行

// 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() 的定义有关,我们必须在其中构造一个 PinBox

void BoardRoom::do_something() {
    PinBox box {
        get_special_pin(),
        m_boards[0].get_pin(),
        m_boards[1].get_pin(),
        m_boards[2].get_pin(),
        m_boards[3].get_pin()
    };

    // other stuff
}

如何使用 get_special_pin() 的结果和 m_boards 的所有元素构造 PinBox,而不必为 m_boards 中的每个引脚写出一行?

(就像我说的,这是专注于实际问题的简化:实际定义分布在不同命名空间中的十几个文件中。一点上下文:引脚是互斥体,Board 是一个数据库对象,PinBox 是 std ::scoped_lock 和 BoardRoom 是一个“实时”服务器对象,必须强制同步以实现持久性保证的一致性)

这里的问题实际上是

PinBox box
的定义不灵活,如果
M_NUM_BOARDS
变大(比如 1024;我目前有 16 个),就会变得不合适。而且它很容易出错,因为手写的
std::array::operator[]
没有边界检查。

是否有更好的方法(不需要每次

M_NUM_BOARDS
更改时都修改 PinBox 定义)?

当然,我们可以引入一个

get_board_pin(int)
之类的

// get a pin
constexpr BoardPin& get_board_pin(int idx) {
    return m_boards[idx].get_pin();
}

使施工变得

PinBox box {
    get_special_pin(),
    get_board_pin(0),
    get_board_pin(1),
    get_board_pin(2),
    get_board_pin(3)
};

这似乎是朝着正确方向迈出的一步,但我真的不确定接下来会发生什么。也许是模板?

任何解决方案,无论多么庞大,我们都将不胜感激。

c++ constructor variadic-templates constexpr
1个回答
0
投票

您可以创建一个工厂函数,您可以将第一个引脚和数组传递给该函数,并使用立即调用的 lambda 函数来构造对象,以扩展以创建一组数组索引,该数组索引可用于将数组扩展为构造函数参数。看起来像

template <typename Pin, std::size_t N>
auto make_pinbox(const Pin& first_pin, const std::array<Board, N>& boards)
{
    return [&]<std::size_t... Is>(std::integer_sequence<size_t, Is...>)
    {
        return PinBox{ first_pin, boards[Is].get_pin()... };
    }(std::make_index_sequence<N>{})();
}
© www.soinside.com 2019 - 2024. All rights reserved.