从移位运算符,逐位运算符和sizeof运算符产生的结果的值类别是什么?

时间:2014-07-01 20:10:22

标签: c++ operators expression language-lawyer

转移运算符:<< >> 逐位运算符:~&^| sizeof运算符:sizeof()

根据C ++标准(n3797),我只能确认~产生prvalue(5.3.1 / 2),而不是上面的其他产品。

4 个答案:

答案 0 :(得分:1)

据我所知,结果是 prvalues ,但这只是一种推测。这似乎与What is the value category of the operands of C++ operators when unspecified?Does the standard mandate an lvalue-to-rvalue conversion of the pointer variable when applying indirection?中涵盖的操作数值类别的方式类似。

我们可以从3.10 部分看到Lvalues和rvalues 有以下注释:

  

第5章中对每个内置运算符的讨论表明了   它产生的价值的类别和价值的类别   它期望的操作数。

但正如我们所看到的,5部分仅在少数情况下明确说明了值类别。对于此特定问题,仅明确说明&~的结果的值类别

即使它没有明确规定,我们也能找到指向一致方向的线索。我们可以提出一个论点,即>><<^|的操作数转换为 prvalues 。这并没有规定结果的值类别,但它确实将结果排除在 xvalue 之后,根据{em> 7 段,其中包含以下注释:

  

表达式是xvalue,如果它是:

     

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

     

- 对rvalue引用的强制转换   对象类型,

     

- 指定a的类成员访问表达式   非对象类型的非静态数据成员   表达式是xvalue,或

     

- a。*指向成员的指针表达式   其中第一个操作数是xvalue,第二个操作数是a   指向数据成员的指针。

     

一般来说,这条规则的效果就是这样   命名的右值引用被视为左值和未命名的右值   对象的引用被视为xvalues;右值引用   无论是否命名,函数都被视为左值。

我没有看到任何合理的论据,结果可能是左值,因此基本上没有 prvalue

所以细节如下:

部分5 一元运算符 2 涵盖~&,其中包含:

  

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

班次运营商需要整合的促销活动,其中包含5.3.1 Shift运算符 1 部分,其中包含:

  

操作数应为整数或无范围的枚举类型,并执行整体促销。

我们可以看到整体促销活动需要<{1}} 整体促销中的 prvalues ,其中每个段落都以:

开头
  

[...]

的prvalue

5.84.5都需要通常的算术转换并且都说:

  

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

因此通常的算术转换的最后一个子句适用于:

  

否则,应对两个操作数执行整数提升(4.5)。 59

经验方法

Luc Danton在他对Empirically determine value category of C++11 expression?的回答中有一种确定表达式价值范畴的经验方法。该方法使用以下代码:

^

并且答案概述了如下逻辑:

  

左值表达式产生左值引用类型,x值为   一个右值引用类型,以及一个只有该类型的prvalue。

以下示例均产生 prvalue see it live ):

|

答案 1 :(得分:0)

sizeof():size_t根据标准5.3.3 pt6 - 标准5.19 / 3表示&#34;整数常量表达式是整数或未整数枚举类型的表达式,隐式转换为prvalue,其中转换后的表达式是一个核心常数表达式。&#34;从5.3.3 / 6和18.2 / 6可以推断出它是一个prvalue。

E1&lt;&lt; E2和E1>&gt; E2:标准5.8.1&#34;操作数应为整数或无范围的枚举类型,并执行整体促销。结果的类型是提升的左操作数的类型。&#34;。根据标准4.5和特定的第7页,积分促销意味着prvalue。

&安培; |和^:标准指定&#34;执行通常的算术转换; (...)运算符仅适用于整数或无范围的枚举操作数&#34;。

答案 2 :(得分:-2)

cppreference说明以下功能
prvaule (&#34; pure&#34; rvalue)是一个标识临时对象(或其子对象)的表达式,或者是与任何对象无关的值。
以下表达式是prvalues:

  1. Literal(字符串文字除外),例如42或true或nullptr。
  2. 函数调用/运算符表达式,如果函数&或运算符的返回类型不是引用,例如str.substr(1,2)或2 + 2
  3. 这适用于功能,我不确定有关内置运营商的规则究竟是什么。

答案 3 :(得分:-3)

有一些小东西: http://rextester.com/DUEJY28518

std::cout << typeid(decltype(sizeof(char))).name() << std::endl;
std::cout << typeid(decltype(1 << 1)).name() << std::endl;
std::cout << typeid(decltype(1 >> 1)).name() << std::endl;
std::cout << typeid(decltype(~1)).name() << std::endl;
std::cout << typeid(decltype(1 & 1)).name() << std::endl;
std::cout << typeid(decltype(1 | 1)).name() << std::endl;
std::cout << typeid(decltype(1 ^ 1)).name() << std::endl;

std::cout << "-------------" << std::endl;
std::cout << typeid(decltype(1U << 1)).name() << std::endl;
std::cout << typeid(decltype(1U >> 1)).name() << std::endl;
std::cout << typeid(decltype(~1U)).name() << std::endl;
std::cout << typeid(decltype(1U & 1)).name() << std::endl;
std::cout << typeid(decltype(1U | 1)).name() << std::endl;
std::cout << typeid(decltype(1U ^ 1)).name() << std::endl;

std::cout << "-------------" << std::endl;
std::cout << typeid(decltype(1L << 1)).name() << std::endl;
std::cout << typeid(decltype(1L >> 1)).name() << std::endl;
std::cout << typeid(decltype(~1L)).name() << std::endl;
std::cout << typeid(decltype(1L & 1)).name() << std::endl;
std::cout << typeid(decltype(1L | 1)).name() << std::endl;
std::cout << typeid(decltype(1L ^ 1)).name() << std::endl;

结果是(MSVC):

unsigned int
int
int
int
int
int
int
-------------
unsigned int
unsigned int
unsigned int
unsigned int
unsigned int
unsigned int
-------------
long
long
long
long
long
long