4

背景

假设我正在尝试使用平面数组实现一个固定大小的多维数组:

template <class T, std::size_t... Dims>
struct multi_array {
    static constexpr std::size_t size() noexcept
    {
        return (Dims * ... * std::size_t{1});
    }
    std::array<T, size()> _elems;
};

_elems成员被公开以启用不可复制、不可移动类型的聚合初始化:(假设non_movable具有显式(int)构造函数)

multi_array<non_movable, 2, 3> arr {
    non_movable(0), non_movable(1), non_movable(2),
    non_movable(3), non_movable(4), non_movable(5)
};

这要归功于 C++17 保证的复制省略 - 的相应元素_elems直接从未实现的纯右值初始化,而不需要移动构造函数。

问题

现在的问题是:在上面的声明中,多维数组像一维数组一样被初始化。我将其称为“平面初始化”,与“嵌套初始化”相反:

multi_array<non_movable, 2, 3> arr {
    { non_movable(0), non_movable(1), non_movable(2) },
    { non_movable(3), non_movable(4), non_movable(5) }
}; // error: too many initializers for 'multi_array<non_movable, 3, 2>'

我们如何才能启用嵌套初始化,而不必将用于实现的底层容器multi_array从一维数组更改为多维数组?

我想这需要一个自定义构造函数,但我不知道如何通过构造函数“透明地”传递未实现的纯右值。我能想到的就是用它们构造一个参数,然后从参数中移动,这对于不可移动的类型不起作用。

最小的可重现示例

#include <array>
#include <cstddef>

struct non_movable {
    explicit non_movable(int) {}
    non_movable(const non_movable&) = delete;
    non_movable(non_movable&&) = delete;
    non_movable& operator=(const non_movable&) = delete;
    non_movable& operator=(non_movable&&) = delete;
    ~non_movable() = default;
};

template <class T, std::size_t... Dims>
struct multi_array {
    static constexpr std::size_t size() noexcept
    {
        return (Dims * ... * std::size_t{1});
    }
    std::array<T, size()> _elems;
};

int main()
{
    multi_array<non_movable, 3, 2> arr {
        non_movable(0), non_movable(1), non_movable(2),
        non_movable(3), non_movable(4), non_movable(5)
    };
    // multi_array<non_movable, 3, 2> arr {
    //     { non_movable(0), non_movable(1), non_movable(2) },
    //     { non_movable(3), non_movable(4), non_movable(5) }
    // };
    (void)arr;
}

现场演示

4

1 回答 1

3

我不知道如何通过构造函数“透明地”传递未实现的纯右值。

您想要的通常是不可能的。一旦prvalue作为参数传递给函数,它将初始化一个对象参数,或者它会显示一个绑定到引用参数的临时值。无论哪种方式,它都不再是prvalue。

您可以为您的特定用例做的最好的事情是将其保留为聚合,并且要么接受您必须将其初始化为“平面”多维数组,要么通过将数组存储在数组中使其成为真正的多维数组。两种选择都有权衡。

于 2020-01-30T14:30:35.103 回答