c++ - 通过引用可变参数函数传递 ND 数组
问题描述
我想让函数multi_dimensional
通过引用接受多维数组。
这可以通过以下适用于的语法的变体来完成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;
}
解决方案
主要问题是您不能使数组维数本身可变。所以无论你走哪条路,你几乎肯定需要某种递归方法来处理各个数组层。这种方法到底应该是什么样子,主要取决于一旦将阵列提供给您,您打算如何处理该阵列。
如果你真正想要的只是一个可以给定任何多维数组的函数,那么只需编写一个可以给定任何东西但只要任何东西都是数组就存在的函数:
template <typename T>
std::enable_if_t<std::is_array_v<T>> multi_dimensional(T& a)
{
constexpr int dimensions = std::rank_v<T>;
// ...
}
然而,这本身很可能不会让你走得很远。要对给定的数组实际做任何有意义的事情,您很可能需要递归遍历子数组。除非您真的只想查看结构的最顶层。
另一种方法是使用递归模板来剥离各个数组级别,例如:
// 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<int, 2, 3, 2>
内部使用扁平表示并将多维索引映射到线性索引。这种方法的一个优点(除了更简洁的语法)是您可以轻松更改映射,例如,从行优先切换到列优先布局,例如,用于性能优化......
为了实现一个具有静态维度的通用n D 数组,我将引入一个辅助类来封装从n D 索引对线性索引的递归计算:
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);
}
推荐阅读
- google-workspace - 团队存储库的团队云端硬盘与 Google 云端硬盘共享文件夹。Team Drive 目前值得吗?
- mongodb - MongoDB ODBC DSN 配置
- java - 尝试以特定方式从 StringBuilder 中删除多个特定字符
- c# - 将 onClick 添加到 Infragistics WebDataGrid
- python - AttributeError:“NoneType”对象在尝试添加多个 keras 密集层时没有属性“_inbound_nodes”
- javascript - 在另一个文件中使用 Ajax 获取动态 PHP 表单 ID
- javascript - AngularJS - 在浏览器关闭之前使用 $window.onbeforeunload 调用 API
- python - django"
我一直在努力解决我认为是我的愚蠢疏忽的事情。我有一个表单,它将输入提供给一个视图,该视图查询我拥有的一些 SQL 表并返回一个列表,其中包含每个表中的列**。
正在发生的奇怪的事情是我的列表出现在
<QuerySet{[ ]}>
每个列表对象的括号。谁能告
- curl - 设置变量等于范围内的模式匹配
- android - java.lang.IllegalStateException:应为 BEGIN_OBJECT 但在第 2 行第 1 列错误为 STRING