初始化 reference_wrapper 的数组

Initialize an array of reference_wrapper

从 C 到 C++,我试图了解智能指针和引用的世界。我有以下内容:

class Game {
public:
    ...
private:
    ...
    static GamePiece EmptyPiece;
    reference_wrapper<GamePiece> _board[N][M] = { ref(Game::EmptyPiece) };
    vector<GamePlayer> _players = vector<GamePlayer>(N_PLAYERS, GamePlayer());
    ...
};

在下面的情况下,我希望每个 Player 持有一个 vector<GamePiece> 和 return 对这些片段的引用,然后放入 _board。但是,我的 _board 的以下初始化会产生

no default constructor exists for class "std::reference_wrapper

我在这里错过了什么?从所有权上看,每个GamePlayer都属于Game(可以看出),而GamePiece肯定属于GamePlayer,这就是为什么我想使用参考资料。

就是这里

reference_wrapper<GamePiece> _board[N][M] = { ref(Game::EmptyPiece) };

您初始化了第一个元素(插入了一些大括号省略),但将其余元素保留为默认初始化。这是不可能发生的,因为 std::reference_wrapper 不能默认初始化(就像它建模的引用一样)。

您可以将原始数组替换为 N*M 大小的 std::vector,并使用适当的构造函数来复制初始化所有元素(就像您对 _players 所做的那样)。当然,索引的计算需要你自己去计算,但是内存是按顺序排列的。

在我看来,初始化引用数组很痛苦。问题是——正如@StoryTeller 在回答中所说——reference_wrapper 不是默认可构造的。

因此您必须编写自己的变通函数。我将 post 编写初始化引用数组的一般问题的代码,不会深入探讨您的问题。

因此请考虑以下情况:您有一个数组 arr 保存支持 operator[] 的某种类型的元素(例如您问题中的 Game)。您需要一个常量或非常量引用数组,该数组中的元素由索引 ind 指定。给你:

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

对于非常量版本,删除此代码中的所有 const 并将 std::cref 替换为 std::ref

用作

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 是一个大小为 2 的数组,它包含对 arr[1]arr[3] 的 const 引用,对于向量也是如此(但请注意对矢量通常不稳定,即通过调整大小或类似操作它们可能会失效)。