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
也会满足
我无法理解为什么 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
也会满足