为什么常量指针不能是常量表达式?
以下程序可以编译:
template <const int * P>
class Test{};
extern const int var = 42; //extern needed to force external linkage
int main()
{
Test<&var> test;
}
但是,这个程序不能编译,这对我来说是一个惊喜:
template <const int * P>
class Test{};
extern const int var = 42; //extern needed to force external linkage
extern const int * const ptr = &var; //extern needed to force external linkage
int main()
{
Test<ptr> test; //FAIL! Expected constant expression.
}
替代示例:
int main()
{
const int size = 42;
int ok[*&size]; //OK
const int * const pSize = &size;
int fail[*pSize]; //FAIL
}
我得出结论,指针不能是常量表达式,无论它是否为 const 并用常量表达式初始化。
问题:
- 我的结论正确吗?
- 如果是这样,为什么指针不能是常量表达式?如果没有,为什么上面的程序不能编译?
- C++0x(C++11,如果你愿意的话)会改变什么吗?
感谢您的任何见解!
The following program compiles:
template <const int * P>
class Test{};
extern const int var = 42; //extern needed to force external linkage
int main()
{
Test<&var> test;
}
This one, however, doesn't, which is a surprise for me:
template <const int * P>
class Test{};
extern const int var = 42; //extern needed to force external linkage
extern const int * const ptr = &var; //extern needed to force external linkage
int main()
{
Test<ptr> test; //FAIL! Expected constant expression.
}
Alternative example:
int main()
{
const int size = 42;
int ok[*&size]; //OK
const int * const pSize = &size;
int fail[*pSize]; //FAIL
}
I have concluded that a pointer just can't be a constant expression regardless of whether it's const and initialized with a constant expression.
Questions:
- Is my conclusion true?
- If so, why can't a pointer be a constant expression? If not, why don't the above programs compile?
- Does C++0x(C++11, if you will) change anything?
Thanks for any insights!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
情况有点复杂。在 C++03 和 C++11 中,如果
var
是本地静态/类静态或命名空间范围变量,则&var
是常量表达式。这称为地址常量表达式。使用该常量表达式初始化类静态或命名空间范围指针变量保证在任何代码运行之前完成(静态初始化阶段),因为它是常量表达式。然而,仅从 C++11 开始,存储地址
&var
的 constexpr 指针变量也可以用作地址常量表达式,并且仅从 C++11 开始,您可以取消引用地址常量表达式(实际上,您可以取消更多引用 - 甚至是本地数组元素地址,但让我们将其保留在主题中),如果它引用在取消引用之前初始化的常量整型变量或 constexpr 变量,您将再次得到常量表达式(根据类型和值类别,常量表达式的种类可能会有所不同)。因此,以下是有效的 C++11:这是标准措辞中的一个已知限制 - 目前仅允许其他模板参数作为参数或
& 。 object
,用于指针类型的模板参数。尽管编译器应该能够做更多的事情。It's a bit more complicated. In C++03 and C++11,
&var
is a constant expression ifvar
is a local static / class static or namespace scope variable. This is called an address constant expression. Initializing a class static or namespace scope pointer variable with that constant expression is guaranteed to be done before any code is run (static initialization phase), because of it being a constant expression.However only since C++11, a constexpr pointer variable that stores the address
&var
can also be used as an address constant expression and only since C++11, you can dereference an address constant expression (actually, you can dereference even more - even local array element addresses, but let's keep it ontopic) and if it refers to a constant integral variable initialized prior to the dereference or a constexpr variable, you again get a constant expression (depending on the type and value category, the kind of constant expression may vary). As such, the following is valid C++11:This is a known limitation in the Standard's wording - it currently only allows other template parameters as arguments or
& object
, for a template parameter of pointer type. Even though the compiler should be capable of doing much more.C++0x 中仍然不允许这样做。 temp.arg.nontype 需要:
原答案:
constexpr
关键字而不是顶级const
。还有一个涉及 gcc 错误,g++ 拒绝标准草案自己的有效
constexpr
用法示例 。It's still not allowed in C++0x.
temp.arg.nontype
requires:original answer:
constexpr
on a pointer. So what you are trying should now be possible, although you must now use theconstexpr
keyword instead of top-levelconst
.There's also a gcc bug involved, g++ rejects the standard draft's own examples of valid
constexpr
usage.问题是因为您的 C++ 程序可以在内存中的任何位置加载,因此每次运行该程序时全局
var
的地址可能不同。如果你运行你的程序两次会发生什么? var 显然位于两个不同的位置。更糟糕的是,在您的示例中,您获取了堆栈上变量的地址!看看这个:
如果 main 调用 myfunction(3),那么会在不同的位置创建 3 个 myvar。编译时甚至无法知道创建了多少个 myvar,更不用说确切的位置了。
最后:将变量声明为 const 意味着:“我保证”,并且 不 意味着它是一个编译时常量。看这个例子:
The problem is because your C++ program can be loaded at any point in memory, and so the address of a global
var
may be different each time you run the program. What happens if you run your program twice?var
is obviously in two different locations then.Even worse, in your example, you take the address of a variable on the stack! look at this:
If main calls myfunction(3), then 3 myvars are created at seperate locations. There's no way for the compile time to even know how many myvars are created, much less there exact locations.
Finally: declaring a variable to be
const
means: "I promise", and does not mean that is a compile time constant. See this example: