C++:为什么这个 constexpr 不是编译时常量

C++: Why is this constexpr not a compile time constant

在以下 C++11 代码中,最后一次调用 arraySize 导致编译错误。显然这是因为 y 是运行时大小的数组,并且无法为 y 推导出 arraySize 模板参数 N。我不明白为什么 x 是编译时大小的数组,但 y 最终是运行时大小的。 arraySize 模板函数直接取自 Scott Meyers 的 "Effective Modern C++" 项目 1.

#include <cstddef>

template<typename T, std::size_t N>
constexpr std::size_t arraySize(T(&)[N]) noexcept { return N; }

struct S
{
    char c[10];
};

int main()
{
    S s;
    S* ps = &s;

    char x[arraySize(s.c)];
    char y[arraySize(ps->c)]; // why is y a runtime sized array?

    arraySize(x);
    arraySize(y); // error !?

    return 0;
}

在 C++ 中,错误不是对 arraySize(y) 的调用,而是 y 本身的声明。

数组声明中的边界必须是 "converted constant expression".

如果你的编译器接受了y的声明,然后告诉你y是一个运行时绑定的数组,那么它就不是C++编译器。在任何已批准的 C++ 版本和当前草案中都没有绑定运行时数组。

arraySize(s.c)arraySize(ps->c)之间的显着区别是ps->c(*ps).c相同,*解引用运算符需要左值到- ps 上的右值转换,它不是常量表达式(&s 也不是,见下文)。表达式的其余部分不涉及左值到右值的转换,数组左值直接由引用绑定。

A constant expression is either a glvalue core constant expression whose value refers to an entity that is a permitted result of a constant expression (as defined below), or a prvalue core constant expression whose value is an object where, for that object and its subobjects:

  • each non-static data member of reference type refers to an entity that is a permitted result of a constant expression, and

  • if the object or subobject is of pointer type, it contains the address of an object with static storage duration, the address past the end of such an object (5.7), the address of a function, or a null pointer value.

An entity is a permitted result of a constant expression if it is an object with static storage duration that is either not a temporary object or is a temporary object whose value satisfies the above constraints, or it is a function.

很明显ps包含了一个自动存储时间对象的地址,所以不能声明constexpr。但是,如果将 S s; S* ps = &s; 更改为 static S s; constexpr S* ps = &s;

,一切都应该开始工作

(另一方面,您会认为 arraySize(s.c) 的参数也不是常量表达式,因为它是一个引用而不是静态存储持续时间的对象)