作为简化,假设我们有两种不同类型的引脚和一个固定其中一种的电路板
// 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)
};
这似乎是朝着正确方向迈出的一步,但我真的不确定接下来会发生什么。也许是模板?
任何解决方案,无论多么庞大,我们都将不胜感激。
您可以创建一个工厂函数,您可以将第一个引脚和数组传递给该函数,并使用立即调用的 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>{})();
}