通过引用可变参数函数传递 N 维数组 [英] Pass N-D array by reference to variadic function

查看:62
本文介绍了通过引用可变参数函数传递 N 维数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想让函数 multi_dimensional 通过引用接受一个多维数组.

I'd like to make the function multi_dimensional accept a multidimensional array by reference.

是否可以通过以下适用于 three_dimensional 的语法变体来实现?

Can this be done with a variation of the syntax below which works for three_dimensional?

#include <utility>

// this works, but number of dimensions must be known (not variadic)
template <size_t x, size_t y, size_t z>
void three_dimensional(int (&nd_array)[x][y][z]) {}

// error: parameter packs not expanded with ‘...’
template <size_t... dims>
void multi_dimensional(int (&nd_array)[dims]...) {}

int main() {
    int array[2][3][2] = {
        { {0,1}, {2,3}, {4,5} },
        { {6,7}, {8,9}, {10,11} }
    };
    three_dimensional(array); // OK
    // multi_dimensional(array); // error: no matching function
    return 0;
}

推荐答案

主要问题是你不能让数组维数本身成为可变参数.所以无论你走哪条路,你几乎肯定需要某种递归方法来处理各个数组层.这种方法究竟应该是什么样子,主要取决于您在阵列被提供给您后究竟打算对它做什么.

The main problem is that you cannot make the number of array dimensions itself variadic. So whichever way you go, you will almost certainly need a recursive approach of some sort to deal with the individual array layers. What exactly such approach should look like will mainly depend on what exactly you're planning to do with the array once it's been given to you.

如果你真的只想要一个可以被赋予任何多维数组的函数,那么只需编写一个可以被赋予任何东西的函数,除了 只存在,只要它是一个数组:

If really all you want is a function that can be given any multi-dimensional array, then just write a function that can be given anything but only exists as long as that anything is an array:

template <typename T>
std::enable_if_t<std::is_array_v<T>> multi_dimensional(T& a)
{
    constexpr int dimensions = std::rank_v<T>;

    // ...
}

但是,这本身很可能不会让您走得很远.要对给定的数组真正做任何有意义的事情,您很可能需要对子数组进行一些递归遍历.除非你真的只想看看结构的最顶层.

However, this by itself will most likely not get you very far. To actually do anything meaningful with the array you've been given, you will most likely need some recursive walking through subarrays. Unless you really just want to look at the topmost layer of the structure.

另一种方法是使用递归模板来剥离各个数组级别,例如:

Another approach is to use a recursive template to peel back the individual array levels, for example:

// we've reached the bottom
template <typename T, int N>
void multi_dimensional(T (&a)[N])
{
    // ...
}

// this matches any array with more than one dimension
template <typename T, int N, int M>
void multi_dimensional(T (&a)[N][M])
{
    // peel off one dimension, invoke function for each element on next layer
    for (int i = 0; i < N; ++i)
        multi_dimensional(a[i]);
}

然而,我建议至少考虑使用 std::array<> 而不是原始数组,因为原始数组的语法和特殊行为往往会将所有内容变成混乱的没时间.一般来说,实现你自己的多维数组类型可能是值得的,比如 NDArray ,它在内部使用扁平表示并且只映射多维索引为线性索引.这种方法的一个优点(除了更简洁的语法)是您可以轻松更改映射,例如,从行优先布局切换到列优先布局,例如,用于性能优化…

I would, however, suggest to at least consider using std::array<> instead of raw arrays as the syntax and special behavior of raw arrays tends to turn everything into a confusing mess in no time. In general, it might be worth to implement your own multi-dimensional array type, like an NDArray<int, 2, 3, 2> which internally works with a flattened representation and just maps multi-dimensional indices to a linear index. One advantage of this approach (besides the cleaner syntax) would be that you can easily change the mapping, e.g., to switch from row-major to column-major layout, e.g., for performance optimization…

为了实现具有静态维度的通用 nD 数组,我将引入一个辅助类来封装从 nD 索引的线性索引的递归计算:

To implement a general nD array with static dimensions, I would introduce a helper class to encapsulate the recursive computation of a linear index from an nD index:

template <std::size_t... D>
struct row_major;

template <std::size_t D_n>
struct row_major<D_n>
{
    static constexpr std::size_t SIZE = D_n;

    std::size_t operator ()(std::size_t i_n) const
    {
        return i_n;
    }
};

template <std::size_t D_1, std::size_t... D_n>
struct row_major<D_1, D_n...> : private row_major<D_n...>
{
    static constexpr std::size_t SIZE = D_1 * row_major<D_n...>::SIZE;

    template <typename... Tail>
    std::size_t operator ()(std::size_t i_1, Tail&&... tail) const
    {
        return i_1 + D_1 * row_major<D_n...>::operator ()(std::forward<Tail>(tail)...);
    }
};

然后:

template <typename T, std::size_t... D>
class NDArray
{
    using memory_layout_t = row_major<D...>;

    T data[memory_layout_t::SIZE];

public:
    template <typename... Args>
    T& operator ()(Args&&... args)
    {
        memory_layout_t memory_layout;
        return data[memory_layout(std::forward<Args>(args)...)];
    }
};


NDArray<int, 2, 3, 5> arr;

int main()
{
    int x = arr(1, 2, 3);
}

这篇关于通过引用可变参数函数传递 N 维数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆