代码之家  ›  专栏  ›  技术社区  ›  senseiwa

定义d维中的数字元组并访问它们

  •  1
  • senseiwa  · 技术社区  · 7 年前

    任务是存储一系列 n 标量 尺寸。想象一下有一个向量,一个矩阵,或者一个 n

    举个例子,我想要一个1D长的数组 4 n == 2 , d == 1 ,在运行时,我说我需要一个

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

    2x4 3双格子( n == 3 , d == 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 -网格的第四个元素?当然是接线员。。。但我想写一封信 操作员返回 引用元组 三个双打。

    给出一个想法:

    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能帮上忙吗?

    1 回复  |  直到 7 年前
        1
  •  2
  •   Jarod42    7 年前

    我变了 MultiArray How 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;
    };
    

    然后添加层以使其适应您的界面( 多阵列 可能写的和 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