constexpr begin of a std::array

constexpr begin of a std::array

本文关键字:array std begin of constexpr      更新时间:2023-10-16

我很难理解为什么 gcc-8.2.0 和 clang-7.0.0 都拒绝以下代码(这里的实时代码(:

#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没问题?同样,如果我们宣布vstatic constexpr,为什么b会变得没问题?问题从根本上在于指针。为了有一个作为指针的常量表达式,它必须始终指向一个已知的、常量的东西。这不适用于没有静态存储持续时间的局部变量,因为它们具有基本可变的地址。但是对于函数局部静力学或全局变量,它们确实有一个常量地址,因此您可以使用常量指针指向它们。


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

常量表达式是 glvalue 核心常量表达式,它引用作为常量表达式(定义如下(的允许结果的实体,或者是其值满足以下约束的 prvalue 核心常量表达式:

  • 如果值是类类型的对象,[...]
  • 如果值为指针类型,则它包含具有静态存储持续时间的对象的地址、超过此类对象末尾的地址 ([expr.add](、函数的地址或 null 指针值,以及
  • [...]

b在第二个项目符号中没有这些东西,所以这失败了。但是global_b满足粗体条件 - 如果v被宣布为staticb也是如此.