gpt4 book ai didi

c++ - 定义 d 维度的数字元组并访问它们

转载 作者:行者123 更新时间:2023-11-30 03:20:16 24 4
gpt4 key购买 nike

我正在尝试一个看似扭曲的想法,但我喜欢挑战,尽管它只是我发明的 C++ 练习。

任务是在 d 维度中存储一系列 n 标量。想象一下,有一个 vector 、矩阵或 n double 或整数或其他任何东西的 3D 矩阵,并在运行时选择有多少(手动计算,没什么特别的)。

比方说,我想要一个长 4 的一维数组,包含两个 double 值(n == 2d == 1,在运行时我说我想要存储 4):

| d0 d1 | d0 d1 | d0 d1 | d0 d1 |

或者 3 个 double 的 2D 2x4 网格(n == 3d == 2,在运行时我说我想要一个2 * 4 的存储):

| d0 d1 d2 | d0 d1 d2 | d0 d1 d2 | d0 d1 d2 |
| d0 d1 d2 | d0 d1 d2 | d0 d1 d2 | d0 d1 d2 |

例如,我如何访问网格的第 i, j 元素?当然,使用运算符......但我想编写一个单个运算符,将引用元组返回给三个 double 。

给出一个想法:

template <std::size_t n, std::size_t d, typename Number>
class storage
{
public:

// Magic tricks here?
auto operator()(std::size_t i_0, ..., std::size_t i_d) -> std::tuple<n std::ref<Number>s>
{

}
};

问题是,我怎样才能在这里玩一些神奇的模板技巧来定义一个返回同类类型元组的运算符?

我发现特别难以思考如何定义该元组,当然还有必须恰好有 d 个参数的运算符。

至于用法,我希望能够像这样工作,例如在 2D 示例中:

 // define a matrix of three doubles
storage<3, 2, double> storageobj(8);

// get a block, these should be references
auto block = storageobj(0, 1);
std::get<0>(block) = -123.456;

请注意,我现在不关心如何访问内存中的元素的实际实现,但返回类型的定义和如何制作 operator() 是主要目标这个练习。

一些神奇的 TMP 能帮上忙吗?

最佳答案

我将 MultiArrayHow to allocate & access 3D, 4D, 5D arrays? 更改为具有一些带有 std::array 的静态大小:

template <typename T, std::size_t Dim>
class MultiArray
{
public:

explicit MultiArray(const std::array<std::size_t, Dim>& dimensions) :
dimensions(dimensions),
values(computeTotalSize(dimensions))
{
assert(!values.empty());
}

const T& get(const std::array<std::size_t, Dim>& indexes) const
{
return values[computeIndex(indexes)];
}
T& get(const std::array<std::size_t>& indexes)
{
return values[computeIndex(indexes)];
}

std::size_t computeIndex(const std::array<std::size_t, Dim>& indexes) const
{
size_t index = 0;
size_t mul = 1;

for (size_t i = 0; i != dimensions.size(); ++i) {
assert(indexes[i] < dimensions[i]);
index += indexes[i] * mul;
mul *= dimensions[i];
}
assert(index < values.size());
return index;
}

std::array<std::size_t, Dim> computeIndexes(std::size_t index) const
{
assert(index < values.size());

std::array<std::size_t, Dim> res;

std::size_t mul = values.size();
for (std::size_t i = dimensions.size(); i != 0; --i) {
mul /= dimensions[i - 1];
res[i - 1] = index / mul;
assert(res[i - 1] < dimensions[i - 1]);
index -= res[i - 1] * mul;
}
return res;
}

private:
std::size_t computeTotalSize(const std::array<std::size_t, Dim>& dimensions) const
{
std::size_t totalSize = 1;

for (auto i : dimensions) {
totalSize *= i;
}
return totalSize;
}

private:
std::array<std::size_t, Dim> dimensions;
std::vector<T> values;
};

然后添加层使其适应您的界面(为了避免这种情况,MultiArray 的编写可能类似于 storage_impl)。

为了将 array<std::size_t, N> 转换为 std::size_t, .., std::size_t ,我们使用 std::index_sequence<0, 1, 2, .., N - 1> 来允许可变参数扩展。然后我们只需要将其转换为类型:

template <std::size_t, typename T>
using always_type = T;

template <std::size_t n, typename Seq, typename Number>
class storage_impl;

template <std::size_t n, typename Number, std::size_t ... Is>
class storage_impl<n, std::index_sequence<Is...>, Number>
{
public:
storage_impl(always_type<Is, std::size_t>... dims) : array{{{dims...}}} ()

std::array<Number, n>&
operator()(always_type<Is, std::size_t>... indexes)
{
return array.get({{indexes...}});
}

const std::array<Number, n>&
operator()(always_type<Is, std::size_t>... indexes) const
{
return array.get({{indexes...}});
}

private:
MultiArray<std::array<Number, n>, sizeof...(Is)> array;
};

最后:

template <std::size_t n, std::size_t d, typename Number>
using storage = storage_impl<n, std::make_index_sequence<d>, Number>;

用法类似于:

// define a 2D matrix of three doubles
storage<3, 2, double> storageobj(2, 4); // matrix 2x4 of std::array<double, 3>

auto&& block = storageobj(0, 1); // std::array<double, 3>&
std::get<0>(block) = -123.456; // or block[0] = -123.456

关于c++ - 定义 d 维度的数字元组并访问它们,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52971550/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com