constexpr是一个std :: array的开头

lin*_*ver 28 c++ constexpr c++17

我无法理解为什么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;
}
Run Code Online (Sandbox Code Playgroud)

有错误

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

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

Bar*_*rry 48

所以让我们回避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
Run Code Online (Sandbox Code Playgroud)

为什么是b错误但是global_b没问题?同样,为什么b如果我们宣布成为好vstatic constexpr?问题基本上与指针有关.为了得到一个指针的常量表达式,它必须始终指向一个已知的常量事物.对于没有静态存储持续时间的局部变量,这实际上不起作用,因为它们具有根本可变的地址.但是对于函数局部静态或全局变量,它们确实有一个常量地址,因此你可以对它们采用常量指针.


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

常量表达式可以是一个glvalue芯常量表达式指的是一个常量表达式的结果允许的实体(如下面所定义),或一个prvalue芯常数表达式,其值满足以下约束条件:

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

b在第二个子弹中没有这些东西,所以这失败了.但global_b满足粗体条件-正如b如果v被宣布static.