11

例如,如果我们有一个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

我们不能以某种方式限制它吗?

4

4 回答 4

16

为确保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 规范没有标记with的const重载。std::array::operator[]constexpr

所以在 C++11 中你不走运。在 C++14 中,您可以使其工作,但array前提是调用索引运算符的 the 和结果均已声明constexpr

澄清

数组索引的 C++11 规范如下:

                reference operator[](size_type n);
          const_reference operator[](size_type n) const;

数组索引的 C++14 规范如下:

                reference operator[](size_type n);
constexpr const_reference operator[](size_type n) const;

Ieconstexpr被添加到constC++14 的重载中。

更新

数组索引的 C++17 规范如下:

constexpr       reference operator[](size_type n);
constexpr const_reference operator[](size_type n) const;

循环现在完成。Universe 可以在编译时计算。;-)

于 2014-12-19T01:12:14.563 回答
8

如果您在编译时知道数组索引,则可以使用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它始终可以在编译时检测到越界。

于 2014-12-19T00:39:39.717 回答
6

an 上的数组访问std::array与常规 C 数组相同,它从不检查索引是否有效,如果超出范围,它只会调用 UB。如果您需要限制,请使用which为超出数组边界的值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"
于 2014-12-19T00:34:57.113 回答
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

然而,这可以产生很多功能。大多数情况下,如果您的设计是合理的,您将永远不需要这种类型的检查。

于 2014-12-19T00:43:41.607 回答