C++ C++;:为什么这个constexpr不是编译时常量
在下面的C++11代码中,最后一次调用arraySize会导致编译错误。显然,这是因为y是运行时大小的数组,并且不能为y推导arraySize模板参数N。我不明白为什么x是编译时大小的数组,但y最终是运行时大小的数组。arraySize模板函数直接取自Scott Meyers的“有效的现代C++”第1项C++ C++;:为什么这个constexpr不是编译时常量,c++,c++11,templates,constexpr,C++,C++11,Templates,Constexpr,在下面的C++11代码中,最后一次调用arraySize会导致编译错误。显然,这是因为y是运行时大小的数组,并且不能为y推导arraySize模板参数N。我不明白为什么x是编译时大小的数组,但y最终是运行时大小的数组。arraySize模板函数直接取自Scott Meyers的“有效的现代C++”第1项 #包括 模板 constexpr std::size_t arraySize(t(&)[N])noexcept{return N;} 结构 { charc[10]; }; int main()
#包括
模板
constexpr std::size_t arraySize(t(&)[N])noexcept{return N;}
结构
{
charc[10];
};
int main()
{
S S;
S*ps=&S;
char x[阵列化(s.c)];
char y[arraySize(ps->c)];//为什么y是运行时大小的数组?
排列(x);
数组化(y);//错误!?
返回0;
}
在C++中,错误不是调用<代码> ARAYSIZE(Y)< /C>,而是声明<代码> 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*ps=&S代码>到<代码>静态S;constexpr S*ps=&S代码>
(另一方面,你可能会认为,arraySize(s.c)
的参数也不是一个常量表达式,因为它是一个引用,而不是静态存储持续时间的对象)我被难倒了。。。s.c
和ps->c
具有相同的类型,正如typeid(s.c).name()
或typeid(ps->c.name()
,即A10_-c
为g++使其更暗一点:如果将arraySize()
的参数作为常量的引用,则编译如下:char y[arraySize(decltype(ps->c)}];
g++和clang++报告y
是可变长度数组,可能更有用<代码>注释:在常量表达式< /代码>中不允许读非CONSTEPRPR变量“ps”吗?“如果编译器接受Y的声明,并且稍后告诉你Y是运行时绑定数组,则它不是C++编译器。”-这部分不是真的,一致的实现(编译器)被明确允许“接受”。(即编译和/或执行)通过扩展的方式进行格式错误的输入,参见N4296草案中的1.4/8。在这种情况下,需要实现发出诊断,除非调用中添加了-pedantic选项,否则GCC和clang不会发出变长数组的警告。
#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;
}