4

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 GamePieces are definitely owned by the GamePlayers, and that's why I want to use references.

4

2 回答 2

2

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.

于 2018-04-15T05:14:02.100 回答
1

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).

于 2018-11-29T00:26:43.433 回答