为什么`std :: array :: at()`没有实现为模板函数?

Car*_*ito 0 c++ c++11 c++14

编辑:我忘了提到这将是在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为了性能和安全而编写自己的课程,这个想法突然出现在我脑海中.

Hen*_*nke 5

您需要能够动态访问元素.仅因为在编译时已知大小并不意味着在编译时已知访问的索引.考虑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)

Live on Godbolt