As a simplification, suppose we have two different kinds of pins and a Board that holds one of them
// 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;
}
};
And a variadic box of pins that we'll need that can hold arbitrary pins:
// 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...)} {};
};
And finally, the room that contains everything and wherein all the activities happen
// 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();
};
The question pertains to the definition of BoardRoom::do_something() where we have to construct a 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
}
How can I construct that PinBox with the result of get_special_pin() and all the elements of m_boards without having to write out a line for each pin in m_boards?
(Like I said, this is a simplification to focus on the actual problem: the actual definitions are spread across a dozen files in varying namespaces. A little context: the pins are mutexes, the Board is a Database object, the PinBox is std::scoped_lock and the BoardRoom is a "live" server object that has to force synchronization for consistency in implementing durability guarantees)
The problem here, really, is that definition of PinBox box is inflexible and would be unweidly if M_NUM_BOARDS grows large (like 1024; I currently have 16). Also it's error-prone as there's no bounds check on the handwritten std::array::operator[].
Is there a better way (that does not require modification of the PinBox definition everytime M_NUM_BOARDS changes)?
Of course, we can introduce a get_board_pin(int) like
// get a pin
constexpr BoardPin& get_board_pin(int idx) {
return m_boards[idx].get_pin();
}
So that the construction becomes
PinBox box {
get_special_pin(),
get_board_pin(0),
get_board_pin(1),
get_board_pin(2),
get_board_pin(3)
};
which seems like a step in the right direction, but I'm really not sure what happens next. Maybe templates?
Any solution, no matter how bulky, would be appreciated.
You can make a factory function that you can pass the first pin and the array to and then construct the object using an immediately invoked lambda function to create a pack of array indices that can be used to expand out the array into constructor parameters. That looks like: