Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/142.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;:为什么这个constexpr不是编译时常量_C++_C++11_Templates_Constexpr - Fatal编程技术网

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

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()

在下面的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()
{
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;
}