我正在研究核心常量表达式*中允许的内容,这在C++标准草案的5.19 常量表达式第2段中有所描述:
条件表达式是核心常量表达式,除非它涉及以下之一作为潜在评估的子表达式(3.2),但是未评估的逻辑AND(5.14),逻辑OR(5.15)和条件(5.16)操作的子表达式不考虑[注意:重载的运算符调用函数.-end note]:
并列出随后的子弹中的排除项并包括(强调我的):
- 具有未定义行为的操作 [注意:包括,例如,有符号整数溢出(第5条),某些指针算术(5.7),除零(5.6)或某些移位操作(5.8) - 结束注释];
嗯?为什么常量表达式需要此子句来涵盖未定义的行为?常量表达式是否有一些特殊的东西需要未定义的行为才能在排除中进行特殊划分?
拥有这个条款是否给了我们没有它的任何优势或工具?
作为参考,这看起来像广义常量表达式提案的最新修订版.
C++ 11中的每个表达式都有一个值类别.lvalue,xvalue或prvalue之一.
有没有办法编写一个宏,给定任何表达式作为参数,将产生一个字符串"lvalue","xvalue"或"prvalue"酌情?
例如:
int main()
{
int x;
cout << VALUE_CAT(x) << endl; // prints lvalue
cout << VALUE_CAT(move(x)) << endl; // prints xvalue
cout << VALUE_CAT(42) << endl; // prints prvalue
}
Run Code Online (Sandbox Code Playgroud)
怎么可以VALUE_CAT实现?
TL; DR
给出以下代码:
int* ptr;
*ptr = 0;
Run Code Online (Sandbox Code Playgroud)
在应用间接之前,是否*ptr需要进行左值到右值的转换ptr?
该标准涵盖了许多地方的左值到左值的主题,但似乎没有指定足够的信息来确定*运算符是否需要这样的转换.
细节
在左值到右值的转换是覆盖在N3485的部分4.1 左值到右值转换段落1和说(重点矿山前进):
可以将非函数非数组类型T的glvalue(3.10)转换为prvalue.53如果T是不完整类型,则需要进行此转换的程序是错误的.如果glvalue引用的对象不是T类型的对象,并且不是从T派生的类型的对象,或者如果该对象未初始化,则需要此转换的程序具有未定义的行为.[...]
那么*ptr = 0; 转换需要吗?
如果我们转到4第1节,它说:
[...] 如果需要,标准转换序列将应用于表达式 ,以将其转换为所需的目标类型.
那么什么时候需要呢?如果我们看一下5 表达式,第9段中提到了左值到右值的转换,它说:
每当glvalue表达式作为操作符的操作数出现时,该操作符需要该操作数的prvalue,左值到右值(4.1),数组到指针(4.2)或函数到指针(4.3)标准转换是用于将表达式转换为prvalue.[...]
和第11段说:
在某些情况下,表达式仅出现其副作用.这样的表达式称为丢弃值表达式.[...]当且仅当表达式是volatile限定类型的左值并且它是以下之一时,才应用左值到右值转换(4.1). ...]
两段似乎都不适用于此代码示例和5.3.1 一元运算符第1段它说:
一元*运算符执行间接:它所应用的表达式应该是指向对象类型的指针,或指向函数类型的指针,结果是指向表达式指向的对象或函数的左值.如果表达式的类型是"指向T的指针",则结果的类型为"T".[注意:通过指向不完整类型(cv void除外)的指向的间接有效.由此获得的左值可以以有限的方式使用(例如,初始化参考); 这个左值不能转换为prvalue,见4.1. - …
前提:
C++ 11 Standard将表达式分为三个不相交的值类别:lvalues,xvalues和prvalues(第3.10/1节).此处提供了对哪些值类别的解释.
我正在努力弄清楚不同运营商对其操作数的价值类别的要求是什么.第3.10/1段规定:
[...]每个表达式都属于此分类法中的基本分类之一:lvalue,xvalue或prvalue.表达式的此属性称为其值类别.[注意:第5章中对每个内置运算符的讨论表明了它产生的值的类别以及它所期望的操作数的值类别.例如,内置赋值运算符期望左操作数是左值,右操作数是prvalue并产生左值作为结果.用户定义的运算符是函数,它们期望和产生的值的类别由它们的参数和返回类型决定. - 尾注]
尽管上面的说明声称,第5条并不总是非常清楚运营商的操作数的价值范畴.例如,关于赋值运算符的操作数的值类别(第5.17/1段),这就是所说的:
赋值运算符(=)和复合赋值运算符都是从右到左分组.所有都需要一个可修改的左值作为左操作数,并返回一个左值操作数的左值.如果左操作数是位字段,则所有情况下的结果都是位字段.在所有情况下,在右和左操作数的值计算之后,以及在赋值表达式的值计算之前,对赋值进行排序.对于不确定序列的函数调用,复合赋值的操作是单个评估.[注意:因此,函数调用不应介入左值到右值的转换和与任何单个复合赋值运算符相关的副作用. - 尾注]
合适的操作数怎么样?
整个5.17节中不再出现"rvalue"和"lvalue"字样.虽然第3.10/1段中的注释明确指出内置赋值运算符期望将prvalue作为右操作数,但在第5.17节中没有明确提到.甚至5.17/1的最后一个注释,提到左值到右值的转换,似乎暗示rvalues是以某种方式预期的(否则转换的需要是什么?),但笔记毕竟是非规范性的.
涉及其他运算符的部分,包括乘法运算符和加法运算符,通常对其操作数的值类别保持沉默.我在标准中找不到任何"默认语句",声明如果没有另外指定,内置运算符的操作数是rvalues.因此,问题.
题:
很高兴参考C++ 11标准.
我一直在互联网上阅读很多,似乎很多人提到了以下规则(但我在标准中找不到它),
加法运算符+(和所有其他二元运算符)要求两个操作数都是rvalue,结果是rvalue.等等..
我检查了C++标准,并明确指出(第3.10/2条),
每当glvalue出现在期望prvalue的上下文中时,glvalue就会转换为prvalue
(第5/9条),
每当glvalue表达式作为操作符的操作数出现时,该操作符需要该操作数的prvalue,左值到右值(4.1),数组到指针(4.2)或函数到指针(4.3)标准转换是用于将表达式转换为prvalue.
它使用一个术语操作数"期望"一个prvalue.但是,当我查看加法运算符,乘法运算符等时,它只提到,结果是一个prvalue,但它没有说明操作数是"预期"的内容.
二元运算符是否真的期望操作数是prvalue在以下情况下会有所不同,
int b = 2;
int a = b + 1;
Run Code Online (Sandbox Code Playgroud)
如果b预期是prvalue,那么这里将进行左值到右值的转换,然后它将执行prvalue + prvalue并返回一个prvalue,结果prvalue被赋值给一个左值a.
但是,如果b不需要是prvalue,则它将是lvalue + prvalue,结果是prvalue.
我真的想知道标准在哪里明确地或隐含地提到不同运营商的规则?我检查了所有运算符部分和只有少数运算符,标准明确提到操作数和结果是左值还是右值.对于大多数运营商而言,标准仅提及结果,而不是操作数要求.
谢谢.
顺便说一下,我在标准5.19中发现关于常量表达式可能非常"隐含地"暗示二元运算符需要对操作数进行左值到右值的转换.有关详细信息,请参阅我之前的问题,
条件表达式是常量表达式,除非它涉及以下之一作为潜在评估的子表达式(3.2).
...
- 除非适用,否则为左值 - 右值转换(4.1)
----一个整数或枚举类型的glvalue,它引用一个带有前面初始化的非易失性const对象,用一个常量表达式初始化
谢谢阅读.