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

如何基于数组值递归裁切Eigen Tensor?模板实例化过深问题求解

问题原因分析

你的递归实现触发模板实例化深度超限,核心原因是运行时条件无法让编译器提前终止模板递归:

  • 每次调用chipTensorRecursive时,TensorType的类型都会改变(chip()返回的是维度减1的TensorChipOp视图类型),编译器会为每个不同的TensorType生成新的模板实例。
  • 由于dim是运行时变量,编译器无法在编译阶段确定dim >= indices.size()的终止条件何时触发,会不断递归实例化模板,直到达到编译器的默认递归深度上限(比如900)。

你的递归思路本身方向没错,但没有利用编译时信息来控制递归终止,导致了不必要的模板爆炸。

可行解决方案

要解决这个问题,需要将维度处理逻辑放到编译时,让编译器能明确递归终止点。以下是两种实现方式:

方式一:利用编译时索引序列(C++14及以上)

通过std::index_sequence将维度索引转化为编译时常量,编译器可以准确控制递归深度:

#include <Eigen/Dense>
#include <unsupported/Eigen/CXX11/Tensor>
#include <iostream>
#include <vector>
#include <utility>

// 递归终止:所有维度处理完成
template<typename TensorType, std::size_t... Is>
auto chipTensorImpl(TensorType& tensor, const std::vector<int>& indices, std::index_sequence<Is...>) {
    return tensor;
}

// 递归处理每个维度
template<typename TensorType, std::size_t I, std::size_t... Is>
auto chipTensorImpl(TensorType& tensor, const std::vector<int>& indices, std::index_sequence<I, Is...>) {
    if (indices[I] == -1) {
        // 跳过当前维度,处理下一个
        return chipTensorImpl(tensor, indices, std::index_sequence<Is...>{});
    } else {
        // 裁切当前维度,递归处理剩余维度
        auto chipped = tensor.chip(indices[I], I);
        return chipTensorImpl(chipped, indices, std::index_sequence<Is...>{});
    }
}

template<typename TensorType>
auto chipTensor(TensorType& tensor, const std::vector<int>& indices) {
    static_assert(TensorType::NumDimensions == indices.size(), "Indices size must match tensor dimensions");
    return chipTensorImpl(tensor, indices, std::make_index_sequence<TensorType::NumDimensions>{});
}

int main() {
    Eigen::Tensor<double, 3> tensor(4, 3, 2);
    std::vector<int> indices = {1, -1, 1};
    tensor.setValues({{{ 0,  1}, { 2,  3}, { 4,  5}}, 
                      {{ 6,  7}, { 8,  9}, {10, 11}}, 
                      {{12, 13}, {14, 15}, {16, 17}}, 
                      {{18, 19}, {20, 21}, {22, 23}}});
    auto result = chipTensor(tensor, indices);
    std::cout << "Result: " << result << std::endl;
    return 0;
}

方式二:C++17折叠表达式(更简洁)

利用折叠表达式一次性处理所有维度,避免显式递归:

#include <Eigen/Dense>
#include <unsupported/Eigen/CXX11/Tensor>
#include <iostream>
#include <vector>
#include <utility>

template<typename TensorType, std::size_t... Is>
auto chipTensorImpl(TensorType tensor, const std::vector<int>& indices, std::index_sequence<Is...>) {
    // 用折叠表达式逐个应用chip操作
    return ((indices[Is] == -1 ? tensor : tensor.chip(indices[Is], Is)) ...);
}

template<typename TensorType>
auto chipTensor(TensorType& tensor, const std::vector<int>& indices) {
    static_assert(TensorType::NumDimensions == indices.size(), "Indices size must match tensor dimensions");
    return chipTensorImpl(tensor, indices, std::make_index_sequence<TensorType::NumDimensions>{});
}

int main() {
    Eigen::Tensor<double, 3> tensor(4, 3, 2);
    std::vector<int> indices = {1, -1, 1};
    tensor.setValues({{{ 0,  1}, { 2,  3}, { 4,  5}}, 
                      {{ 6,  7}, { 8,  9}, {10, 11}}, 
                      {{12, 13}, {14, 15}, {16, 17}}, 
                      {{18, 19}, {20, 21}, {22, 23}}});
    auto result = chipTensor(tensor, indices);
    std::cout << "Result: " << result << std::endl;
    return 0;
}
关于递归方案的合理性

你的初始递归思路是合理的,但没有结合编译时信息来控制递归终止。Eigen的Tensor操作都是基于模板的编译时多态,所有维度相关的逻辑最好放到编译时处理,这样既可以避免模板实例化爆炸,还能让编译器进行更多优化。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 11:31:07