You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何将任意大小的std::array作为模板非类型参数传递并自动推导其大小?

如何将任意大小的std::array作为模板非类型参数传递并自动推导其大小?

刚好我之前也纠结过这个问题,C++20的新特性刚好能完美解决你的需求,完全不用搞那种加break值的丑陋hack!

先直接给你解决核心问题的代码,再慢慢解释:

单个std::array的情况(自动推导大小)

你之前的写法编译失败,是因为N还没声明就被使用了,这确实是个语法问题。不过别担心,我们可以用C++20支持的auto作为std::array的大小占位符,让编译器自动从初始化列表里推导数组大小:

#include <array>

// 用std::array<int, auto>作为非类型模板参数,auto会自动推导大小N
template <std::array<int, auto> Arg>
void bar() {
    // 直接通过Arg.size()获取推导出来的大小,用std::tuple_size_v也可以
    constexpr std::size_t N = Arg.size();
    // 这里就可以放心使用N和Arg了,比如遍历数组元素:
    for (std::size_t i = 0; i < N; ++i) {
        // 处理Arg[i]的逻辑
    }
}

int main() {
    // 调用的时候直接传初始化列表,编译器自动推导N=2
    bar<{1, 2}>();
}

扩展到你的实际需求:两个std::array参数

你需要传递两个独立的数组,并且保持它们的分组意义,那只需要把模板参数扩展成两个std::array<int, auto>就行了,调用方式完全符合你的预期:

#include <array>

template <std::array<int, auto> Arr1, std::array<int, auto> Arr2>
void foo() {
    // 分别获取两个数组的大小,都是编译器自动推导的
    constexpr std::size_t Size1 = Arr1.size();
    constexpr std::size_t Size2 = Arr2.size();

    // 比如遍历第一个数组
    for (std::size_t i = 0; i < Size1; ++i) {
        // 处理Arr1[i]的业务逻辑
    }
    // 遍历第二个数组
    for (std::size_t j = 0; j < Size2; ++j) {
        // 处理Arr2[j]的业务逻辑
    }
}

int main() {
    // 完全按照你想要的方式调用,编译器自动推导第一个数组大小3,第二个4
    foo<{1, 2, 3}, {4, 5, 6, 7}>();
}

为什么这个写法可行?

C++20开始允许std::array作为非类型模板参数,同时支持用auto作为模板参数的占位符——这里的std::array<int, auto>里的auto,会让编译器根据你传递的初始化列表的元素数量,自动推导对应的大小值N,完全不需要你手动声明或指定N,完美绕开了“N用在声明之前”的语法限制。

对比你之前想的hack方法

那种加break值的写法确实太不优雅了:调用的时候看着别扭,函数内部还要额外写逻辑找分隔符、拆分两组数据,不仅容易出错,维护起来也麻烦。而用上面的写法:

  1. 调用方式直观清晰,完全符合你对两组数据的分组需求
  2. 函数内部直接拿到两个独立的数组,不需要任何额外的分割逻辑,处理起来更简单
  3. 类型安全,不会因为break值和业务数据冲突而出问题

注意事项

这个写法需要C20或更高版本的编译器支持,因为用到了C20才有的两个核心特性:

  • 允许std::array作为非类型模板参数
  • 支持用auto作为模板参数的占位符(包括std::array的大小参数)

从你提到的“C++20开始可以用std::array作为非类型参数”来看,这个解法完全适配你的场景。

火山引擎 最新活动