编辑:我忘了提到这将是在constexpr没有任何动态指数的背景下.
考虑以下(非常天真)的实现:
template <class T, std::size_t N>
class array
{
// ...
template <size_type pos>
reference at()
{
static_assert(pos < N, "Index out of range.");
return m_data[pos];
}
}
Run Code Online (Sandbox Code Playgroud)
具有以下用途:
int main()
{
array<int, 5> a{1, 2, 3, 4, 5};
cout << a.at(10) << "\n"; // will throw at runtime
cout << a.at<10>() << "\n"; // static assert error; index out of range
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这有效地防止了对类型和任何令人讨厌的段错误或异常的范围访问.编译器会抛出一个错误,如下所示:
error: static assertion failed: Index out of range
static_assert(pos < N, "Index out of range");
Run Code Online (Sandbox Code Playgroud)
大多数IDE都会捕获错误的访问权限.那么为什么没有这样实现呢?
注意:如果这很明显,我很抱歉,但我打算array为了性能和安全而编写自己的课程,这个想法突然出现在我脑海中.
您需要能够动态访问元素.仅因为在编译时已知大小并不意味着在编译时已知访问的索引.考虑a.at(i)这里i是用户输入.
此外,该at函数需要按标准执行运行时检查,请参阅[sequence.reqmts]
成员函数
at()提供对容器元素的边界检查访问.at()抛出out_of_range如果n >= a.size().
另外,从C++ 17开始,at成员函数被标记为constexpr,因此对于在编译时保持不变的索引,问题中的模板化函数没有区别.
#include <array>
int main() {
constexpr std::array<int,5> a = { 1, 2, 3, 4, 5 };
constexpr int b = a.at(2);
constexpr int c = a.at(10);
}
Run Code Online (Sandbox Code Playgroud)
Live on Wandbox (错误信息是meh ...)
如果您在编译时知道索引并且不想支付at在C++ 17之前产生的额外成本,那么您可以使用std::get<10>(a).此变体具有零开销,因为编译器可以完全内联阵列访问
#include <array>
int test(std::array<int,5> const &a) {
return std::get<1>(a);
}
Run Code Online (Sandbox Code Playgroud)