You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++基于CRTP实现多维数组的线性索引计算及维度存储方案

核心问题分析

你的设计主要存在两个核心冲突点:

  1. 静态数组的维度是编译期常量,动态数组的维度是运行期可变值,不能共用同一套模板化的索引计算逻辑
  2. 你当前的CRTP派生类参数传递错误,且动态数组用tuple存可变维度的思路不成立,tuple的元素数量和值都是编译期固定的,无法满足运行期Resize的需求

修正方案

1. 新增运行期版本的索引计算函数

新增支持动态维度的ComputeIndex重载,和原有的编译期版本并行:

#include <span>
// 原有的编译期版本保留
template <std::size_t, typename T>
using HookTypeToPack = T;

template <std::size_t ...Dims>
constexpr std::size_t ComputeIndex(HookTypeToPack<Dims, std::size_t> ...multi_index)
{
  constexpr std::size_t dims_arr[] = {Dims...};
  std::size_t multi_index_arr[] = {multi_index...};

  std::size_t index(0), factor(1);
  for(int i = 0; i < sizeof...(Dims); i++)
  {
    assert(0 <= multi_index_arr[i] && multi_index_arr[i] < dims_arr[i]);
    index += factor * multi_index_arr[i];
    factor *= dims_arr[i];
  }

  assert(0 <= index && index < (Dims * ...));
  return index;
}

// 新增运行期版本
constexpr std::size_t ComputeIndex(std::span<const std::size_t> dims, std::span<const std::size_t> multi_index)
{
    assert(dims.size() == multi_index.size());
    std::size_t index = 0, factor = 1;
    for (std::size_t i = 0; i < dims.size(); ++i) {
        assert(multi_index[i] < dims[i]);
        index += factor * multi_index[i];
        factor *= dims[i];
    }
    return index;
}

template <class T, std::size_t size>
constexpr auto InitStaticArray(const T& value)
{
  std::array<T, size> arr;
  std::fill(arr.begin(), arr.end(), value);
  return arr;
}

2. 重写CRTP基类的下标运算符

用C++20的if constexpr自动匹配静态/动态数组的索引计算逻辑:

template <class derived, class T>
class MultiDimArray
{
private:
  constexpr derived& Derived() noexcept { return static_cast<derived&>(*this); }
  constexpr const derived& Derived() const noexcept { return static_cast<const derived&>(*this); }

protected:
  constexpr MultiDimArray() = default;

public:
  template <std::same_as<std::size_t>... Is>
  constexpr const T& operator()(Is... is) const {
    static_assert(sizeof...(Is) >= 1, "下标参数数量不能为0");
    const auto idx = [&] {
      if constexpr (requires { derived::is_static; }) {
        // 静态数组分支:调用编译期索引计算
        return []<std::size_t... Ds>(std::index_sequence<Ds...>, Is... is) {
          return ComputeIndex<Ds...>(is...);
        }(derived::dims_v, is...);
      } else {
        // 动态数组分支:调用运行期索引计算
        assert(sizeof...(Is) == Derived().m_dims.size());
        return ComputeIndex(Derived().m_dims, std::array<std::size_t, sizeof...(Is)>{is...});
      }
    }();
    return Derived().data()[idx];
  }

  template <std::same_as<std::size_t>... Is>
  constexpr T& operator()(Is... is) {
    return const_cast<T&>(std::as_const(*this).operator()(is...));
  }
};

3. 修正静态多维数组实现

修正CRTP参数传递错误,新增编译期维度标识:

template <class T, std::size_t ...Dims>
class StaticMultiDimArray : public std::array<T, (Dims * ...)>,
                            public MultiDimArray<StaticMultiDimArray<T, Dims...>, T>
{
private:
  constexpr static std::size_t n_entries = (Dims * ...);
  friend MultiDimArray<StaticMultiDimArray<T, Dims...>, T>;

public:
  // 编译期标识和维度导出
  constexpr static bool is_static = true;
  constexpr static auto dims_v = std::index_sequence<Dims...>{};

  constexpr StaticMultiDimArray() : std::array<T, n_entries>(InitStaticArray<T, n_entries>(T{})) {}
};

4. 修正动态多维数组实现

用std::vector<std::size_t>存储运行期维度,完善Resize逻辑:

template <class T>
class DynamicMultiDimArray : public std::vector<T>, public MultiDimArray<DynamicMultiDimArray<T>, T>
{
private:
  std::size_t n_entries = 0;
  std::vector<std::size_t> m_dims;
  friend MultiDimArray<DynamicMultiDimArray<T>, T>;

public:
  DynamicMultiDimArray() = default;

  template <typename... Dims>
  requires (std::same_as<Dims, std::size_t> && ...)
  DynamicMultiDimArray(Dims... dimensions) : std::vector<T>((dimensions * ...), T{}) {
    Resize(dimensions...);
  }

  template <typename... Dims>
  requires (std::same_as<Dims, std::size_t> && ...)
  void Resize(Dims... dimensions)
  {
    m_dims = {dimensions...};
    n_entries = (dimensions * ...);
    this->resize(n_entries, T{});
  }
};

使用示例

int main() {
  // 静态数组测试 2x3
  StaticMultiDimArray<int, 2, 3> static_arr;
  static_arr(0, 0) = 1;
  static_arr(1, 2) = 5;
  assert(static_arr(0, 0) == 1);
  assert(static_arr(1, 2) == 5);

  // 动态数组测试 3x4
  DynamicMultiDimArray<int> dynamic_arr(3U, 4U);
  dynamic_arr(2U, 3U) = 10;
  assert(dynamic_arr(2U, 3U) == 10);
  // 运行期Resize为2x2
  dynamic_arr.Resize(2U, 2U);
  dynamic_arr(1U,1U) = 7;
  assert(dynamic_arr(1U,1U) == 7);
}

额外优化建议

不推荐公开继承std::array和std::vector,标准容器没有虚析构函数,公开继承容易出现内存泄漏风险,改为组合形式更安全。

内容的提问来源于stack exchange,提问作者niran90

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 12:36:03