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

C++如何实现可包装可调用对象的constexpr数组完成编译时下标校验

方案1:最小改动实现编译期越界检查

不需要修改原有代码的数组和std::function定义,仅在FunToCall模板中添加静态断言即可实现编译期越界校验:

// 原有代码不变,仅修改FunToCall实现
template <int i> FunT FunToCall() {
    static_assert(i >= 0 && i < a.size(), "index out of bound");
    return a[i];
}

std::array::size是编译期常量,静态断言会在模板实例化阶段触发,只要传入的索引越界会直接编译报错,不会等到运行期抛出异常。

方案2:实现constexpr版本数组

std::function因为存在非平凡析构函数,不属于字面量类型,无法用于constexpr变量声明,要实现constexpr数组需要替换std::function为字面量类型的可调用对象:

核心调整点

  • 将FunT从std::function改为普通函数指针类型,函数指针属于字面量类型,符合constexpr要求
  • 调整lambda实现为无捕获模式,将Foo实例作为调用参数传入,无捕获lambda可隐式转换为函数指针,支持constexpr上下文

完整可运行代码

#include <array>

struct Foo {
    void m1(int) {}
    int* m2() { return &x; }
    int x = 0;
};

// 改用函数指针类型,属于字面量类型
using FunT = bool(*)(Foo&, int);

constexpr FunT Make1(void(Foo::*pf)(int)) {
    return [pf](Foo& foo, int arg) {
        (foo.*pf)(arg);
        return true;
    };
}

constexpr FunT Make2(int*(Foo::*pf)()) {
    return [pf](Foo& foo, int arg) {
        [[maybe_unused]] auto res = (foo.*pf)();
        return true;
    };
}

// 现在可以正常声明为constexpr数组
static constexpr std::array a = {
  Make1(&Foo::m1),
  Make2(&Foo::m2)
};

template <int i> constexpr FunT FunToCall() {
    static_assert(i >= 0 && i < a.size(), "FunToCall index out of range");
    return a[i];
}

template <int... is> bool make_calls(Foo& foo, int arg) {
    return (FunToCall<is>()(foo, is) && ...);
}

int main() {
    Foo foo;
    make_calls<0,1>(foo, 5); // 正常编译运行
    // make_calls<0,1,2>(foo, 5); // 编译报错,触发静态断言
}

该方案要求编译器支持C++17及以上标准,无额外运行时开销,同时满足编译期越界检查和constexpr数组的要求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 20:06:02