Reputation: 3991
Coming from C to C++, I'm trying to understand the world of smart pointers & references. I've got the following:
class Game {
public:
...
private:
...
static GamePiece EmptyPiece;
reference_wrapper<GamePiece> _board[N][M] = { ref(Game::EmptyPiece) };
vector<GamePlayer> _players = vector<GamePlayer>(N_PLAYERS, GamePlayer());
...
};
In the following situation, I would like each Player
to hold a vector<GamePiece>
and return references to these pieces, and put then in the _board
. However, the following initialization of my _board
yields
no default constructor exists for class "std::reference_wrapper
What am I missing here? In terms of ownership, each GamePlayer
is owned by the Game
(as can be seen), and the GamePiece
s are definitely owned by the GamePlayer
s, and that's why I want to use references.
Upvotes: 4
Views: 3644
Reputation: 15498
Initializing an array of references is pain in my opinion. The problem is -- as said in the answer by @StoryTeller -- that a reference_wrapper
is not default constructible.
So you have to write your own workaround functions. I'll post code for the general problem of initializing an array of references and won't dive deeply into your question.
So consider the following case: you have an array arr
holding elements of some type (e.g. a Game
as in your question) that supports operator[]
. You want an array of const- or non-const references to elements in this array specified by the indices ind
. Here you go:
template<typename arr_t, size_t ... I>
auto get_const_reference_array(arr_t const& arr, std::array<size_t, sizeof ...(I)> const& ind, std::index_sequence<I...>)
{
using T = std::decay_t<decltype(std::declval<arr_t>().operator[](size_t{}))>;
return std::array<std::reference_wrapper<const T>, sizeof ...(I)> { std::cref(arr[std::get<I>(ind)]) ... };
}
template<typename arr_t, size_t dim>
auto get_const_reference_array(arr_t const& arr, std::array<size_t, dim> const& ind)
{
return get_const_reference_array(arr, ind, std::make_index_sequence<dim>{});
}
For the non-const version, remove all const
's in this code and replace std::cref
by std::ref
.
Use it as
std::array<int,5> arr{{1,3,5,7,9}};
std::array<size_t,2> ind{{1,3}};
auto ref_arr = get_const_reference_array(arr, ind);
std::vector<int> vec{{1,3,5,7,9}};
auto ref_vec = get_const_reference_array(vec, ind);
ref_arr
then is an array of size 2
which holds const references to arr[1]
and arr[3]
, and the same for the vector (note however that references to a vector are in general not stable, i.e. by resizing or similar actions they might get invalidated).
Upvotes: 1
Reputation: 170123
It's this here
reference_wrapper<GamePiece> _board[N][M] = { ref(Game::EmptyPiece) };
You initialize the first element (with some brace elision thrown in) but leave the rest default initialized. Which can't happen, since std::reference_wrapper
cannot be default initialized (just like the reference it models).
You can substitute the raw array for a std::vector
of N*M
size, and use the appropriate constructor which will copy initialize all the elements (like you do for _players
). Of course, you'll need to do the calculations for indexing by yourself, but the memory will be laid out sequentially.
Upvotes: 3