#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; }
解决方法
数组声明中的边界必须是“转换的常量表达式”.
如果你的编译器接受y的声明,后来告诉你y是运行时绑定的数组,它不是一个C编译器. C的任何批准版本中没有运行时间限制的数组,也没有当前的草案.
arraySize(sc)和arraySize(ps-> c)之间的显着差异在于ps-> c与(* ps).c相同,* dereference操作符需要在ps上进行lvalue-to-rvalue转换,不是一个恒定的表达(也不是& s,见下文).表达式的其余部分不涉及到lvalue-to-rvalue转换,数组lvalue直接由引用绑定.
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,andif 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 * ps =& s;静态S; constexpr S * ps =& s;
(另一方面,你会认为arraySize(s.c)的参数也不是一个常量表达式,因为它是一个引用,而不是静态存储持续时间的对象)