在C ++ 11中获取局部变量的地址是否为常量表达式? [英] Is taking the address of a local variable a constant expression in C++11?

查看:165
本文介绍了在C ++ 11中获取局部变量的地址是否为常量表达式?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下C ++ 11程序:

  int x = 42; 

void f()
{
int y = 43;

static_assert(& x<& y,foo);
}

int main()
{
f();
}

不能使用gcc 4.7编译,因为它抱怨:

 错误:'& y'不是常量表达式

这将符合我的直觉。 y 的地址可能会随着 f 的每次调用而改变,因此当然不能在翻译期间计算。



然而,5.19 [expr.const]中的项目符号似乎无法将其作为常量表达式。



我看到的只有两个竞争者:


一个左值到右值的转换...


但除非我错了(?)程序中没有左值到右值的转换。




一个 id-expression 是指变量[snip]




  • 使用常量表达式初始化


其中 y 是 - 它使用常量表达式 43 / p>

这是标准中的错误,还是我缺少的东西?



更新: / strong>



这很奇怪,但我认为我是最好的,所以让我举一个例子,说明发生了什么: p>

  int x = 42; 

void f()
{
int y = 43;

//地址常量表达式:
constexpr int * px =& x; // OK
constexpr int * py =& y; //错误:局部变量的指针上下文

//布尔常量表达式:
constexpr bool bx =& x; // OK
constexpr bool by =& y; // OK

//比较常数表达式:
constexpr bool eq =(& x ==& y); // OK
constexpr bool lt =(& x<& y); //错误:未定义的行为违反了
常量表达式
}

int main()
{
f();
}

首先区分核心常量表达式(5.19p2)和常量表达式5.19p4)。常数表达式的特定子表达式只需要是核心常量表达式,而不是常量表达式。也就是说,作为常量表达式是完整表达式的属性,而不是子表达式。它还需要查看使用完整表达式的上下文。



因此,结果是gcc错误是误导。首先& y 可能是一些上下文中的常量表达式。其次,原因& x< & y 不是常量表达式是因为比较了无关的指针,而不是子表达式& y p>

解决方案

让我们尝试确定 static_assert-声明中的表达式必须满足逐步


em> static_assert-declaration:

static_assert( constant-expression string-literal );


[dcl.dcl] / 4


static_assert-声明常量表达式应为可以上下文转换为 bool 的常量表达式。


[expr.const] / 4


>参考常量表达式和地址常量表达式称为常数表达式







那么什么类型的常量表达式& x< & y 不是地址常量表达式:



[expr.const] / 4


地址常量表达式是类型的核​​心常量表达式(根据上下文需要转换后) std :: nullptr_t 或指针类型[...]。


$ c>& x< & y $ $



它不是一个引用常量表达式,因此它必须是一个字面常量表达式,如果


一个字面常量表达式是一个proreue核心常量表达式[...]


< blockquote>

因此,& x< & y 必须满足核心常量表达式的要求。






TemplateRex指出 hvd ,在这个特殊情况下,& x< & y 不符合核心常量表达式的要求:



[expr.const] / 2


[核心常量表达式不得包含]未指定结果的关系或等于运算符;


[expr.rel] / 2


如果两个指针 p q 指向不是同一对象或同一数组的元素的成员的不同对象,不同的函数,或者如果它们中只有一个为空,则 p p> q code> p <= q ,未定义 p> = q


但是,对于像

  int arr [2] = { 2}; 
static_assert(& a [0]<& a [1],);

表达式 a + 1 也满足此要求。


The following C++11 program:

int x = 42;

void f()
{
        int y = 43;

        static_assert(&x < &y, "foo");
}

int main()
{
        f();
}

Doesn't compile with gcc 4.7 as it complains:

error: ‘&y’ is not a constant expression

This would agree with my intuition. The address of y potentially changes with each invocation of f, so of course it cannot be calculated during translation.

However none of the bullet points in 5.19 [expr.const] seem to preclude it from being a constant expression.

The only two contenders I see are:

an lvalue-to-rvalue conversion...

but unless I am mistaken (?) there are no lvalue-to-rvalue conversions in the program.

And

an id-expression that refers to a variable [snip] unless:

  • it is initialized with a constant expression

which y is - it is initialized with the constant expression 43.

So is this an error in the standard, or am I missing something?

Update:

It's confusing as hell, but I think I am on top of it, so let me show an example that will show off what is going on:

int x = 42;

void f()
{
        int y = 43;

        // address constant expressions:    
        constexpr int* px = &x; // OK
        constexpr int* py = &y; // ERROR: pointer context for local variable

        // boolean constant expressions:
        constexpr bool bx = &x; // OK
        constexpr bool by = &y; // OK

        // comparison constant expressions:
        constexpr bool eq = (&x == &y); // OK
        constexpr bool lt = (&x < &y); // ERROR: undefined behaviour disqualifies 
                                                 a constant expression
}

int main()
{
        f();
}

First distinguish between a core constant expression (5.19p2) and a constant expression (5.19p4). Specifcally sub-expressions of a constant expression only have to be core constant expressions, not constant expressions. That is, being a constant expression is a property of the full expression, not sub-expressions. It further requires to look at the context it which the full expression is used.

So, as it turns out the gcc error is misleading. Firstly &y may be a constant expression in some contexts. Secondly, the reason &x < &y isn't a constant expression is because of the comparison of unrelated pointers, not of the sub-expression &y.

解决方案

Let's try to determine which requirements the expression in the static_assert-declaration has to fulfil step-by-step, using n3485.

[dcl.dcl]/1

static_assert-declaration:
static_assert (constant-expression,string-literal) ;

[dcl.dcl]/4

In a static_assert-declaration the constant-expression shall be a constant expression that can be contextually converted to bool.

[expr.const]/4

Collectively, literal constant expressions, reference constant expressions, and address constant expressions are called constant expressions.


So what type of constant expression is &x < &y? It is not an address constant expression:

[expr.const]/4

An address constant expression is a prvalue core constant expression (after conversions as required by the context) of type std::nullptr_t or of pointer type [...].

The type of &x < &y is bool as per [expr.rel]/1.

It isn't a reference constant expression either, so it must be a literal constant expression, if any.

A literal constant expression is a prvalue core constant expression of literal type [...]

Therefore, &x < &y has to fulfil the requirements of a core constant expression.


As pointed out by TemplateRex and hvd in the comments, in this particular case, &x < &y does not fulfil the requirements of a core constant expression:

[expr.const]/2

[a core constant expression must not contain] a relational or equality operator where the result is unspecified;

[expr.rel]/2

If two pointers p and q of the same type point to different objects that are not members of the same object or elements of the same array or to different functions, or if only one of them is null, the results of p<q, p>q, p<=q, and p>=q are unspecified.

However, for an example like

int arr[2] = {1, 2};
static_assert(&a[0] < &a[1], "");

The expression a < a+1 fulfils this requirement as well.

这篇关于在C ++ 11中获取局部变量的地址是否为常量表达式?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆