能否为std::array实现编译期边界检查:常量索引越界报错,变量索引正常?
问题描述
考虑如下C++类:
template <int N> class A { private: std::array<double, N> m_vs = {}; public: int size() {return N;} void set_value(double d, int n=0) {m_vs[n] = d;} double get_value(int n=0) {return m_vs[n];} };
假设我们实例化了 a = A<10>(),希望调用 a.set_value(1, 20) 时编译器抛出错误(已知该索引越界),但调用 a.set_value(1, i) 时不报错(i可能为合法索引)。请问是否可以实现该行为?
实现方案
可以实现,核心是区分编译期常量索引和运行期变量索引:对编译期常量做静态检查,运行期变量则保留原逻辑(也可按需添加运行时断言)。以下是两种常用实现方式:
方式一:重载模板版本的成员函数
为set_value和get_value新增模板重载,专门处理编译期整数常量索引,通过static_assert在编译阶段拦截越界:
#include <array> #include <stdexcept> template <int N> class A { private: std::array<double, N> m_vs = {}; public: int size() {return N;} // 处理运行期变量索引的版本 void set_value(double d, int n=0) { // 可选:添加运行时检查,避免运行期越界崩溃 if (n < 0 || n >= N) { throw std::out_of_range("Index out of bounds"); } m_vs[n] = d; } // 处理编译期常量索引的版本 template <int Idx> void set_value(double d) { static_assert(Idx >= 0 && Idx < N, "Compile-time index out of bounds"); m_vs[Idx] = d; } // get_value同理实现重载 double get_value(int n=0) { if (n < 0 || n >= N) { throw std::out_of_range("Index out of bounds"); } return m_vs[n]; } template <int Idx> double get_value() { static_assert(Idx >= 0 && Idx < N, "Compile-time index out of bounds"); return m_vs[Idx]; } };
使用示例:
- 编译期常量索引:调用模板版本
a.set_value<20>(1),编译器会触发static_assert直接报错; - 运行期变量索引:调用普通版本
a.set_value(1, i),仅执行运行期逻辑(可选择去掉运行时检查完全保留原行为)。
方式二:C++20 constexpr上下文判断(无需重载)
利用C++20引入的std::is_constant_evaluated(),直接在原函数内判断当前是否处于编译期常量求值上下文,针对性执行检查:
#include <array> #include <type_traits> template <int N> class A { private: std::array<double, N> m_vs = {}; public: int size() {return N;} void set_value(double d, int n=0) { // 若n是编译期常量,触发静态检查 if constexpr (std::is_constant_evaluated()) { static_assert(n >= 0 && n < N, "Compile-time index out of bounds"); } // 运行期逻辑(可选添加运行时断言) m_vs[n] = d; } double get_value(int n=0) { if constexpr (std::is_constant_evaluated()) { static_assert(n >= 0 && n < N, "Compile-time index out of bounds"); } return m_vs[n]; } };
这种方式无需重载函数:
- 传入
20这类字面量时,std::is_constant_evaluated()返回true,触发static_assert编译报错; - 传入变量
i时,该值无法在编译期确定,跳过静态检查直接执行运行期逻辑。
注意:std::is_constant_evaluated()的判断依赖编译器对常量上下文的识别,复杂场景下需注意边界,但直接传入字面量的场景完全适用。
内容的提问来源于stack exchange,提问作者tst
相关产品推荐
相关产品推荐

