例如,如果我们有一个std::array
并且使用constexpr
实例化一个超出约束的元素,编译器就不会报告错误:
constexpr int EvaluateSpecialArrayIndex(int a)
{ return a * sizeof(int); }
array<int, 5> arr;
cout << arr[98] << endl; //compiles fine
cout << arr[EvaluateSpecialArrayIndex(4)] << endl; //the same as above
我们不能以某种方式限制这个吗?
答案 0 :(得分:13)
为确保在编译时评估constexpr
函数,必须强制它们生成结果constexpr
。例如:
#include <array>
int
main()
{
constexpr std::array<int, 5> arr{1, 2, 3, 4, 5};
int i = arr[6]; // run time error
}
然而:
#include <array>
int
main()
{
constexpr std::array<int, 5> arr{1, 2, 3, 4, 5};
constexpr int i = arr[6]; // compile time error
}
不幸的是,为了实际工作,std::array
必须符合C ++ 14规范,而不是C ++ 11规范。由于C ++ 11规范未使用const
标记std::array::operator[]
的{{1}}重载。
所以在C ++ 11中,你运气不好。在C ++ 14中,您可以使它工作,但前提是constexpr
和调用索引运算符的结果都声明为array
。
<强>澄清强>
用于数组索引的C ++ 11规范读取:
constexpr
用于数组索引的C ++ 14规范读取:
reference operator[](size_type n);
const_reference operator[](size_type n) const;
即。 reference operator[](size_type n);
constexpr const_reference operator[](size_type n) const;
已添加到C ++ 14的constexpr
重载中。
<强>更新强>
用于数组索引的C ++ 17规范读取:
const
循环现已完成。可以在编译时计算Universe。 ; - )
答案 1 :(得分:7)
如果您在编译时知道数组索引,则可以将std::get
与索引一起使用,如果超出范围,将导致编译失败
std::array<int, 4> a{{1,2,3,4}};
std::get<4>(a); // out of bounds, fails to compile
我从gcc-4.9得到的错误以:
结尾error: static assertion failed: index is out of bounds
static_assert(_Int < _Nm, "index is out of bounds");
std::get
仅适用于常量表达式索引(索引是模板参数),因此对于std::array
,它始终可以在编译时检测到越界。
答案 2 :(得分:6)
std::array
上的数组访问对于常规C数组是相同的,它从不检查索引是否有效,如果它超出范围,它只调用UB。如果您需要限制,请使用std::array::at()
,它会对超出数组边界的值抛出std::out_of_range()
异常。
arr.at(EvaluateSpecialArrayIndex(4)); // terminate called after throwing
// an instance of 'std::out_of_range'
如果您想要编译时错误,请使用std::get
:
std::get<EvaluateSpecialArrayIndex(4)>(arr); // error: static_assert failed
// "index is out of bounds"
答案 3 :(得分:2)
简单的回答,因为std::array
分别constexpr
重载来检查这类事情是非常昂贵的。如果需要,可以在std::array
周围编写自己的包装器,为编译时常量提供编译检查访问。类似的东西:
template<typename T, size_t S>
class safeArray
{
std::array<T, S> m_arr;
public:
template<size_t A>
T& safeAt() {
static_assert(A < S, "Index out of bounds");
return m_arr[A];
}
// other funcs as needed
};
然后,您可以执行以下操作:
safeArray<int, 5> arr;
cout << arr.safeAt<98>() << endl; // compile error
然而,这可以产生许多功能。大多数情况下,如果您的设计合理,您将不需要这种类型的检查。