在以下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
自身的声明。
数组声明中的边界必须是“转换后的常量表达式”。
如果您的编译器接受的声明,y
并且以后告诉您这y
是运行时绑定的数组,则它不是C ++编译器。在任何已批准的C ++版本中,也没有当前运行时绑定的运行时数组。
之间的显著差arraySize(s.c)
和arraySize(ps->c)
是ps->c
相同(*ps).c
和*
引用操作需要在左值到右值转换ps
,这不是一个常量表达式(也不是&s
,见下文)。表达式的其余部分不涉及左值到右值的转换,数组左值直接由引用绑定。
常量表达式可以是glvalue核心常量表达式,其值指向作为常量表达式允许的结果(定义如下)的实体,或者是prvalue核心常量表达式,其值是对象,对于该对象及其子对象,其中:
每个引用类型的非静态数据成员都引用一个实体,该实体是常量表达式的允许结果,并且
如果对象或子对象是指针类型,则它包含具有静态存储持续时间的对象的地址,该对象末尾的地址(5.7),函数的地址或空指针值。
如果实体是具有静态存储持续时间的对象,而该对象不是临时对象,或者是其值满足上述约束的临时对象,或者它是一个函数,则该实体是常量表达式的允许结果。
显然ps
包含具有自动存储持续时间的对象的地址,因此无法声明它constexpr
。但是,如果您更改S s; S* ps = &s;
为static S s; constexpr S* ps = &s;
(另一方面,您会认为to的参数arraySize(s.c)
也不是常量表达式,因为它是对静态存储持续时间的引用而不是对象)
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句