移位运算符,逐位运算符和sizeof运算符产生的结果的值类别是什么? [英] What is the value category of result yielded from shift operators, bit-wise operators, and sizeof operator?

查看:172
本文介绍了移位运算符,逐位运算符和sizeof运算符产生的结果的值类别是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

移位运算符:< >>
逐位运算符: code>〜,& ^ $ / code code code code code code code code
$ b $标准(n3797),我只能确认产生prvalue(5.3.1 / 2),而不是上面的其他。

解决方案

据我所知,结果是 prvalues ,但这只是一个猜测。这似乎是以与中所涵盖的操作数的值类别相似的方式指定的,未指定的C ++运算符?应用间接时,标准是否要求指针变量的左值转换? / a>。



我们可以从 3.10 中看到Lvalues和rvalues 以下注意事项:


条款5中每个内置运算符的讨论表明其产生的价值的
类别,

但是我们可以看到 5


操作数的值类别。 code>仅在少数情况下仅显示值类别。在这个特定问题的情况下,只能明确说明& 〜的结果的值类别 code>。



即使它不明确,我们可以找到指向我们一致方向的线索。我们可以提出一个论据:>> ^ | 转换为 prvalues 。这不表示结果的价值类别,但它似乎根据 5 段落排除了 的结果。




表达式是xvalue,如果它是:



- 调用
函数的结果,无论是隐式还是显式,其返回类型是对象类型的
rvalue引用,



- 转换为
对象类型的rvalue引用



- 一个类成员访问表达式,指定
非静态数据成员对象
表达式是一个x值的非参考类型,或者
中的一个。*指向对象的表达式,或


$ b

第一个操作数是一个x值,第二个操作数是
指向数据成员的指针。



一般来说,这个规则的效果是
命名的rvalue引用被视为左值和未命名的rva lue
对象的引用被视为xvalues;
函数的rvalue引用被视为无价值的左值。


我没有看到任何合理的论据结果可能是一个价值,所以基本上让我们有一个 prvalue



所以细节如下:



& 5.3.1 一元运营商段落 2 说:



< blockquote>

以下一元运算符的结果是一个prvalue。


移位运算符需要 5.8 移位运算符段落 1 中所述的整体升级,其中说明:


操作数应为整数或非范围枚举类型,并执行整体升级。


,我们可以看到积分促销要求 prvalu es 从 4.5 整体促销活动在每一段中都说:


[...]


两个 ^ | 需要通常的算术转换,并且都说:



< blockquote>

运算符仅适用于整数或非范围的枚举操作数


因此,通常的算术转换适用于:


否则,对两个操作数执行积分晋升(4.5) sup> 59


经验方法


$ b $ Luc Danton在他的答案中有一个经验性的方法来确定表达式的价值类别:
经验确定C ++的价值类别11表达式?该方法使用以下代码:

  template< typename T> 
struct value_category {
//或者可以是一个整数或枚举值
static constexpr auto value =prvalue;
};

template< typename T>
struct value_category< T&> {
static constexpr auto value =lvalue;
};

template< typename T>
struct value_category< T&&> {
static constexpr auto value =xvalue;
};

//双括号确保我们检查表达式
//不是一个实体
#define VALUE_CATEGORY(expr)value_category< decltype((expr))> ::价值

,答案概述了以下逻辑:


一个lvalue表达式导致一个左值引用类型,
中的一个值为rvalue引用类型的xvalue,只有该类型为prvalue。


以下示例全部产生 prvalue 看到它

  int x = 10 ,y = 2; 
int& xr = x;
int& yr = y;

std :: cout<<< VALUE_CATEGORY(x< y)<< std :: endl
std :: cout<<< VALUE_CATEGORY(10< 2)< std :: endl
std :: cout<<< VALUE_CATEGORY(xr<< yr)<< std :: endl

std :: cout<<< VALUE_CATEGORY(x | y)<< std :: endl
std :: cout<<< VALUE_CATEGORY(10 | 2)<< std :: endl

std :: cout<<< VALUE_CATEGORY(x ^ y)<< std :: endl
std :: cout<<< VALUE_CATEGORY(10 ^ 2)<< std :: endl

std :: cout<<< VALUE_CATEGORY(sizeof(int))<< std :: endl
std :: cout<<< VALUE_CATEGORY(sizeof(x))<< std :: endl


Shift operators: << >> bit-wise operators: ~, &, ^, | sizeof operator: sizeof()

Per the C++ standard (n3797), I can only confirm that ~ yields prvalue (5.3.1/2), but not the others above.

解决方案

As far as I can tell the results are prvalues but that is just a speculative. This seems to be under-specified in a similar way to the value categories of operands which is covered in What is the value category of the operands of C++ operators when unspecified? and Does the standard mandate an lvalue-to-rvalue conversion of the pointer variable when applying indirection?.

We can see from section 3.10 Lvalues and rvalues has the following note:

The discussion of each built-in operator in Clause 5 indicates the category of the value it yields and the value categories of the operands it expects.

but as we can see section 5 only spells out the value category explicitly in a few cases. In the case of this particular question only spells out explicitly the value category of the result for & and ~.

Even though it is underspecified we can find clues that point us in a consistent direction. We can make an argument that the operands for >>, <<, ^ and | are converted to prvalues. This does not dictate the value category of the result but it does seem to exclude the result being an xvalue as per section 5 paragraph 7 which has the following note:

An expression is an xvalue if it is:

— the result of calling a function, whether implicitly or explicitly, whose return type is an rvalue reference to object type,

— a cast to an rvalue reference to object type,

— a class member access expression designating a non-static data member of non-reference type in which the object expression is an xvalue, or

— a .* pointer-to-member expression in which the first operand is an xvalue and the second operand is a pointer to data member.

In general, the effect of this rule is that named rvalue references are treated as lvalues and unnamed rvalue references to objects are treated as xvalues; rvalue references to functions are treated as lvalues whether named or not.

I don't see any reasonable argument that the result could be an lvalue so that basically leaves us with a prvalue.

So the details are as follows:

Both ~ and & are covered by section 5.3.1 Unary operators paragraph 2 which says:

The result of each of the following unary operators is a prvalue.

The shift operators require the integral promotions which is covered in section 5.8 Shift operators paragraph 1 which says:

The operands shall be of integral or unscoped enumeration type and integral promotions are performed.

and we can see that the integral promotions require prvalues from section 4.5 Integral promotions which says in every paragraph starts with:

A prvalue of [...]

Both ^ and | require the usual arithmetic conversions and both say:

operator applies only to integral or unscoped enumeration operands

and therefore the last clause of the usual arithmetic conversions applies which says:

Otherwise, the integral promotions (4.5) shall be performed on both operands.59

Empirical approach

Luc Danton has an empirical approach to determining the value category of an expression in his answer to Empirically determine value category of C++11 expression?. The approach uses the following code:

template<typename T>
struct value_category {
    // Or can be an integral or enum value
    static constexpr auto value = "prvalue";
};

template<typename T>
struct value_category<T&> {
    static constexpr auto value = "lvalue";
};

template<typename T>
struct value_category<T&&> {
    static constexpr auto value = "xvalue";
};

// Double parens for ensuring we inspect an expression,
// not an entity
#define VALUE_CATEGORY(expr) value_category<decltype((expr))>::value

and the answer outlines the logic as follows:

an lvalue expression results in an lvalue reference type, an xvalue in an rvalue reference type, and a prvalue in just the type.

The following examples all yield prvalue (see it live):

int x = 10, y = 2 ;
int &xr = x ;
int &yr = y ;

std::cout << VALUE_CATEGORY( x << y ) << std::endl ;
std::cout << VALUE_CATEGORY( 10 << 2 ) << std::endl ;
std::cout << VALUE_CATEGORY( xr << yr ) << std::endl ;

std::cout << VALUE_CATEGORY( x | y ) << std::endl ;
std::cout << VALUE_CATEGORY( 10 | 2 ) << std::endl ;

std::cout << VALUE_CATEGORY( x ^ y ) << std::endl ;
std::cout << VALUE_CATEGORY( 10 ^ 2 ) << std::endl ;

std::cout << VALUE_CATEGORY( sizeof( int ) ) << std::endl ;
std::cout << VALUE_CATEGORY( sizeof( x ) ) << std::endl ;

这篇关于移位运算符,逐位运算符和sizeof运算符产生的结果的值类别是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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