获取用于多维访问的线性索引
Get linear index for multidimensional access
我正在尝试实现一个多维 std::array,它保存一个大小为 Dim-n-1 * Dim-n-2 * ... * Dim-1 的连续内存数组。为此,我使用来自 std::array 的私有继承:
constexpr std::size_t factorise(std::size_t value)
{
return value;
}
template<typename... Ts>
constexpr std::size_t factorise(std::size_t value, Ts... values)
{
return value * factorise(values...);
}
template<typename T, std::size_t... Dims>
class multi_array : std::array<T, factorise(Dims...)>
{
// using directive and some stuff here ...
template<typename... Indexes>
reference operator() (Indexes... indexes)
{
return base_type::operator[] (linearise(std::make_integer_sequence<Dims...>(), indexes...)); // Not legal, just to explain the need.
}
}
例如,multi_array<5, 2, 8, 12> arr; arr(2, 1, 4, 3) = 12;
将访问线性索引idx = 2*(5*2*8) + 1*(2*8) + 4*(8) + 3
。
我想我必须使用 std::integer_sequence,将整数序列传递给 linearise 函数和索引列表,但我不知道该怎么做。我想要的是这样的:
template<template... Dims, std::size_t... Indexes>
auto linearise(std::integer_sequence<int, Dims...> dims, Indexes... indexes)
{
return (index * multiply_but_last(dims)) + ...;
}
multiply_but_last乘以除最后一个维度之外的所有剩余维度(我看到如何使用 constexpr 可变参数模板函数(例如 for factorise(实现,但我不明白 std::integer_sequence 是否可以(。
我是可变参数模板操作和 std::integer_sequence 的新手,我认为我错过了一些东西。是否有可能在没有开销的情况下获得线性索引计算(即,如果操作是手写的(?
非常感谢您的帮助。
以下内容可能会有所帮助:
#include <array>
#include <cassert>
#include <iostream>
template <std::size_t, typename T> using alwaysT_t = T;
template<typename T, std::size_t ... Dims>
class MultiArray
{
public:
const T& operator() (alwaysT_t<Dims, std::size_t>... indexes) const
{
return values[computeIndex(indexes...)];
}
T& operator() (alwaysT_t<Dims, std::size_t>... indexes)
{
return values[computeIndex(indexes...)];
}
private:
size_t computeIndex(alwaysT_t<Dims, std::size_t>... indexes_args) const
{
constexpr std::size_t dimensions[] = {Dims...};
std::size_t indexes[] = {indexes_args...};
size_t index = 0;
size_t mul = 1;
for (size_t i = 0; i != sizeof...(Dims); ++i) {
assert(indexes[i] < dimensions[i]);
index += indexes[i] * mul;
mul *= dimensions[i];
}
assert(index < (Dims * ...));
return index;
}
private:
std::array<T, (Dims * ...)> values;
};
演示
我用折叠表达式代替了你的factorize
(C++17(。
我有一个非常简单的函数,可以将多维索引转换为一维索引。
#include <initializer_list>
template<typename ...Args>
inline constexpr size_t IDX(const Args... params) {
constexpr size_t NDIMS = sizeof...(params) / 2 + 1;
std::initializer_list<int> args{params...};
auto ibegin = args.begin();
auto sbegin = ibegin + NDIMS;
size_t res = 0;
for (int dim = 0; dim < NDIMS; ++dim) {
size_t factor = dim > 0 ? sbegin[dim - 1] : 0;
res = res * factor + ibegin[dim];
}
return res;
}
如果您看到类似
non-constant-expression cannot be narrowed from type 'int'
的警告,您可能需要将"-Wno-c++11-narrowing"标志添加到编译器中。
用法示例:
2D 阵列
int array2D[rows*cols];
// Usually, you need to access the element at (i,j) like this:
int elem = array2D[i * cols + j]; // = array2D[i,j]
// Now, you can do it like this:
int elem = array2D[IDX(i,j,cols)]; // = array2D[i,j]
3D 阵列
int array3D[rows*cols*depth];
// Usually, you need to access the element at (i,j,k) like this:
int elem = array3D[(i * cols + j) * depth + k]; // = array3D[i,j,k]
// Now, you can do it like this:
int elem = array3D[IDX(i,j,k,cols,depth)]; // = array3D[i,j,k]
ND 阵列
// shapes = {s1,s2,...,sn}
T arrayND[s1*s2*...*sn]
// indices = {e1,e2,...,en}
T elem = arrayND[IDX(e1,e2,...,en,s2,...,sn)] // = arrayND[e1,e2,...,en]
请注意,传递给IDX(...)
的形状参数从第二个形状开始,在本例中s2
。
顺便说一句:此实现需要C++ 14。
- 数组索引的值没有增加
- 芬威克树(BIT).找到具有给定累积频率的最小索引,单位为 O(logN)
- 查找最接近的大于当前数字的数字的索引
- 在C++中调整向量中的索引
- 重载元组索引运算符-C++
- 给定一个向量,如何找到该向量的所有子集和的原始索引
- 为std::string的某个索引赋值
- 并行用于C++17中数组索引范围内的循环
- 向量上的线性搜索
- 跟随整数索引列表的自定义类迭代器
- 如何在for循环中包含两个索引值的测试条件
- D3D11-将混合权重和索引传递到顶点着色器
- 一般采用可索引/可调用的线性组合
- 获取用于多维访问的线性索引
- 特征 3 断言在求解线性系统时失败 - 据我所知,这是由于特征中的无效索引
- 如何在cv :: cuda :: ptrstepszf数据上使用线性索引
- 如何从Arrayfire明确获取线性索引
- 负x,y坐标为线性阵列索引
- 使用提升 MPL 线性化索引
- 线性搜索返回数组,索引值在