std::array 的 constexpr 开头

constexpr begin of a std::array

我无法理解为什么 gcc-8.2.0 和 clang-7.0.0 都拒绝以下代码(实时代码 here):

#include <array>

int main() {

    constexpr std::array<int,3> v{1,2,3};
    constexpr auto b = v.begin(); // error: not a constexpr 
    return 0;
}

有错误

error: '(std::array<int, 3>::const_pointer)(& v.std::array<int,3>::_M_elems)' 
is not a constant expression (constexpr auto b = v.begin();)

根据en.cppreference.com,声明begin()成员函数constexpr。这是编译器错误吗?

所以让我们回避 std::array 让这更容易一些:

template <typename T, size_t N>
struct array {
    T elems[N];

    constexpr T const* begin() const { return elems; }
};

void foo() {
    constexpr array<int,3> v{{1, 2, 3}};
    constexpr auto b = v.begin(); // error
}

constexpr array<int, 3> global_v{{1, 2, 3}};
constexpr auto global_b = global_v.begin(); // ok

为什么 b 是错误的,而 global_b 是正常的?同样,如果我们将 v 声明为 static constexpr,为什么 b 会变得正常?问题基本上是关于指针的。为了拥有一个作为指针的常量表达式,它必须始终指向一个已知的常量。这对于没有静态存储持续时间的局部变量实际上不起作用,因为它们具有根本可变的地址。但是对于函数局部静态或全局变量,它们确实有一个常量地址,所以你可以用一个常量指针指向它们。


在标准语中,来自 [expr.const]/6

A constant expression is either a glvalue core constant expression that refers to an entity that is a permitted result of a constant expression (as defined below), or a prvalue core constant expression whose value satisfies the following constraints:

  • if the value is an object of class type, [...]
  • if the value is of pointer type, it contains the address of an object with static storage duration, the address past the end of such an object ([expr.add]), the address of a function, or a null pointer value, and
  • [...]

b 是第二个项目符号中那些东西的 none,所以这失败了。但是 global_b 满足粗体条件 - 如果 v 被声明为 static.

,则 b 也会满足