为什么常量指针不能是常量表达式?
-
29-10-2019 - |
题
以下程序编译: 通用标签
但是,这不是,这让我感到惊讶: 通用标签
替代示例: 通用标签
我已经得出结论,无论指针是否为const并使用常量表达式初始化,指针都不能是常量表达式。
问题:
- 我的结论正确吗?
- 如果是这样,为什么指针不能是常量表达式?如果没有,为什么上面的程序不能编译?
- C ++ 0x(如果需要,可以使用C ++ 11)更改任何内容吗?
感谢您的见解!
解决方案
有点复杂。在C ++ 03和C ++ 11中,如果&var
是局部static / class static或命名空间范围变量,则var
是常量表达式。这称为地址常量表达式。可以保证在运行任何代码之前(静态初始化阶段)使用该常量表达式初始化类静态或名称空间作用域指针变量,因为它是一个常量表达式。
但是,仅从C ++ 11开始,用于存储地址&var
的 constexpr 指针变量也可以用作地址常量表达式,并且仅从C ++ 11开始,您才可以取消引用地址常量表达式(实际上,您甚至可以取消引用-甚至包括本地数组元素地址,但让我们保留其为主题),如果它引用的是在取消引用之前初始化的常量整数变量或constexpr变量,则您将再次获得一个常量表达式(类型和值类别,常量表达式的种类可能会有所不同)。因此,以下是有效的C ++ 11:
通用标签
如果是这样,为什么指针不能是常量表达式?如果没有,为什么上面的程序不能编译?
这是标准措辞中的一个已知限制-当前,它仅允许将其他模板参数用作指针类型的模板参数的自变量或
& object
。即使编译器应该能够做更多的事情。
其他提示
在C ++ 0x中仍然不允许。 temp.arg.nontype
要求:
非类型,非模板模板参数的模板参数应为以下之一:
- 对于整数或枚举类型的非类型模板参数,使用该模板参数类型的转换后的常数表达式(5.19);或
- 非类型模板参数的名称;或
- 一个常数表达式(5.19),用于指定具有静态存储持续时间和 外部或内部链接或具有外部或内部链接的功能,包括功能模板 和功能模板ID,但不包括非静态类成员,表示为(忽略括号)为
&
id-expression
,但如果&指代函数或数组,并且&可以省略,则&可以省略 如果相应的模板参数是参考,则将其省略;或- 一个常量表达式,其结果为空指针值(4.10);或
- 一个常量表达式,其值为空成员指针值(4.11);或
- 指向成员的指针,如5.3.1所述。
原始答案:
- 在C ++ 03中,只有整数表达式可以是常量表达式。
- 因为标准是这样(自然)这样的。
- 在C ++ 0x中,n3290包括在指针上使用
constexpr
的示例。因此,尽管现在必须使用constexpr
关键字而不是顶层const
关键字,但您现在应该可以尝试执行该操作。还存在一个gcc错误, g ++拒绝了标准草案自己的有效
constexpr
用法示例。。
问题是因为您的C ++程序可以在内存中的任何位置加载,因此,每次运行该程序时,全局var
的地址可能会有所不同。如果两次运行程序会怎样?然后,var
显然位于两个不同的位置。
更糟糕的是,在您的示例中,您采用了堆栈上变量的地址!看这个: 通用标签
如果main调用myfunction(3),则会在单独的位置创建3个myvar。编译时间甚至无法知道如何创建许多 myvars,更不用说确切的位置了。
最后:声明一个变量为const
意味着:“我保证”,而不是意味着这是一个编译时间常数。参见以下示例:
通用标签