标签: lvalue-to-rvalue

左值隐式转换的左值

我看到整个C++标准中许多地方使用的术语"左值到右值转换".据我所知,这种转换通常是隐含的.

标准中的一个意外(对我来说)特征是他们决定将左值作为转换处理.如果他们说glvalue总是可以接受而不是prvalue怎么办?这句话实际上会有不同的含义吗?例如,我们读到lvalues和xvalues是glvalues的例子.我们没有读到lvalues和xvalues可以转换为glvalues.意义上有区别吗?

在我第一次遇到这个术语之前,我曾经或多或少地对lvalues和rvalues进行了如下建模:"lvalues 总是能够充当rvalues,但另外还可以出现在左侧=和右侧&".

对我来说,这是一个直观的行为,如果我有一个变量名,那么我可以将该名称放在我想放置文字的地方.此模型似乎与标准中使用的左值到右值隐式转换术语一致,只要保证发生此隐式转换即可.

但是,因为他们使用这个术语,我开始想知道在某些情况下是否可能无法进行隐式左值到右值转换.也就是说,也许我的心理模型在这里是错误的.以下是该标准的相关部分:(感谢评论者).

每当glvalue出现在期望prvalue的上下文中时,glvalue就会转换为prvalue; 见4.1,4.2和4.3.[注意:尝试将rvalue引用绑定到左值不是这样的上下文; 见8.5.3 .-结束说明]

我理解他们在说明中描述的内容如下:

int x = 1;
int && y = x; //in this declaration context, x won't bind to y.
// but the literal 1 would have bound, so this is one context where the implicit 
// lvalue to rvalue conversion did not happen.  
// The expression on right is an lvalue. if it had been a prvalue, it would have bound.
// Therefore, the lvalue …
Run Code Online (Sandbox Code Playgroud)

c++ implicit-conversion lvalue-to-rvalue c++11

41
推荐指数
2
解决办法
1万
查看次数

结构化绑定是否应作为 C++20 中的右值从函数返回?

考虑一个 C++20 程序,其中函数中foo有一个结构化绑定auto [y]。函数返回y,它被转换为对象类型AA可以从右值引用的常量引用构造。

#include <tuple>
#include <iostream>

struct A {
    A(const int &) { std::cout << "A(const int &) "; }
    A(int &&) { std::cout << "A(int &&) "; }
};

A foo() {
    auto [y] = std::make_tuple(1);
    return y;
}

int main() { foo(); }
Run Code Online (Sandbox Code Playgroud)

根据C++20语言标准应该选择哪一个构造函数?

Clang 选择A(const int &)和 GCC 选择A(int &&),演示:https : //gcc.godbolt.org/z/5q779vE6T

是否有一个编译器不支持这方面的标准?

c++ language-lawyer lvalue-to-rvalue c++20

23
推荐指数
1
解决办法
336
查看次数

在应用间接时,标准是否要求对指针变量进行左值到右值的转换?

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; 转换需要吗?

如果我们转到41节,它说:

[...] 如果需要,标准转换序列将应用于表达式 ,以将其转换为所需的目标类型.

那么什么时候需要呢?如果我们看一下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++ pointers indirection language-lawyer lvalue-to-rvalue

19
推荐指数
2
解决办法
775
查看次数

swap()会导致未定义的行为吗?

我试图std::swap从[C++ 11:utility.swap]中了解条件.模板定义为

template <typename T> void swap(T &, T &)
Run Code Online (Sandbox Code Playgroud)

(加上一些noexcept细节)并具有"交换存储在两个位置的值"的效果.

以下程序是否有明确定义?

#include <utility>

int main()
{
    int m, n;
    std::swap(m, n);
}
Run Code Online (Sandbox Code Playgroud)

如果我自己编写交换代码(即int tmp = m; m = n; n = tmp;),它将具有未定义的行为,因为它将尝试对未初始化的对象进行左值到右值的转换.但标准std::swap函数似乎没有任何强加于它的条件,也不能从规范中得出有任何左值到右值并因此有UB.

标准是否需要std::swap执行一些在未初始化对象上明确定义的魔法?

为了澄清这一点,请考虑函数void f(int & n) { n = 25; },该函数从未具有未定义的行为(因为它不读取n).

c++ undefined-behavior language-lawyer lvalue-to-rvalue c++11

16
推荐指数
2
解决办法
719
查看次数

类型的非const引用的初始化无效

在下面的代码中,我无法将临时对象作为参数传递给printAge函数:

struct Person {
  int age;
  Person(int _age): age(_age) {}
};

void printAge(Person &person) {
   cout << "Age: " << person.age << endl;
}

int main () {
  Person p(50);
  printAge(Person(50));  // fails!
  printAge(p);
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

我得到的错误是:

error: invalid initialization of non-const reference of type ‘Person&’ from an rvalue of type ‘Person’
Run Code Online (Sandbox Code Playgroud)

我意识到这与将lValue传递给期望rValue的函数有关...有没有办法通过使用std :: move或其他东西将我的lValue转换为rValue?我尝试了一个常量参数,但这似乎不起作用.

c++ pass-by-reference lvalue-to-rvalue

16
推荐指数
2
解决办法
3万
查看次数

为什么C++默认不移动构造rvalue引用?

说我有以下功能

void doWork(Widget && param)  // param is an LVALUE of RRef type
{
    Widget store = std::move(param); 
}
Run Code Online (Sandbox Code Playgroud)

为什么我需要param回到rvalue std::move()?是不是很明显,paramrvalue 的类型是因为它在函数签名中被声明为右值引用?不应该仅仅根据这个原则自动调用移动构造函数吗?

为什么不默认发生这种情况?

c++ rvalue-reference move-constructor lvalue-to-rvalue stdmove

12
推荐指数
1
解决办法
953
查看次数

我想我可能想出了一个rvalue数组类型的例子

C++03§4.2N°1:
类型为"NT的数组"或"T的未知边界数组"的左值或右值可以转换为"指向T的指针"的右值.结果是指向数组的第一个元素.

很长一段时间以来我在这个陈述中令人困惑的是,我不太明白阵列类型的右值是什么意思.也就是说,我无法想出一个表达式,其类型是一个数组,结果是一个右值.我读了这个帖子,基本上问了同样的问题,接受的答案是"不,没有数组类型的右值".我想我可能与此矛盾.

C++03§5.2.5N°4 :(关于表达式E1.E2)
如果E2是非静态数据成员,E1的类型是"cq1 vq1 X",E2的类型是"cq2" vq2 T",表达式指定由第一个表达式指定的对象的命名成员.如果E1是左值,则E1.E2是左值.

我认为否则它是一个右值(假设E2不是参考,那个案例被覆盖§5.2.5 N°3)因此......

struct A
{
   int a[4];
};
A f()
{
   A a;
   return a; 
}
int main()
{
   f().a; //I think this is an rvalue of array type...
}
Run Code Online (Sandbox Code Playgroud)

我在这里看到两个选项:
选项1:我是正确的,欢呼,是的,很酷.在这种情况下,问题是:还有其他例子吗?
选项2:我不对,在这种情况下问题是:这是标准的缺陷吗?

我不知道1,但我真的怀疑2,因为当他们谈论函数到指针的转换时,他们只提到了函数类型的左值(很明显没有这样的rvalues).所以他们很可能已经考虑了数组类型的rvalues.

所以,基本上我的问题是我是否提出了数组类型右值的例子,如果没有,请提供一个有效的,我坚信它存在.

c++ arrays rvalue lvalue-to-rvalue

11
推荐指数
1
解决办法
527
查看次数

整数参数调用浮点重载和浮点参数调用整数重载

今天我大致遇到了以下代码:

\n
#include <iostream>\n\nvoid f(float&& f) { std::cout << f << "f "; }\nvoid f(int&& i) { std::cout << i << "i "; }\n\nint main()\n{\n    int iv = 2; float fv = 1.0f;\n    f(2);  f(1.0f);\n    f(iv); f(fv);\n}\n
Run Code Online (Sandbox Code Playgroud)\n

神箭链接

\n

正如预期的那样,前两个 f 调用 print 2i 1f

\n

现在对于第二行,我预计它要么根本不编译,因为 iv 和 fv 不是临时变量(因此不能绑定到 r 值引用),要么它创建要传递给函数的变量的副本,从而打印2i 1f再次打印。

\n

然而,不知何故它打印2f 1i,这几乎是我最没想到的事情。

\n

如果将代码复制到 cppinsights 中,它会将调用转换为

\n
f(static_cast<float>(iv));\nf(static_cast<int>(fv));\n
Run Code Online (Sandbox Code Playgroud)\n

所以它看起来非常有意地将整数转换为浮点数,然后将浮点数转换为整数,但我不知道为什么这样做,也不知道如何谷歌。为什么会出现这种情况?导致这个结果的规则是什么?

\n

c++ overloading reference rvalue-reference lvalue-to-rvalue

11
推荐指数
1
解决办法
205
查看次数

数组和右值

$ 4.2/1 - "类型的左值或右值"数组"N T"或"未知T的数组"可以转换为"指向T的指针"的右值.结果是一个指向第一个元素的指针阵".

我不知道如何在初始化/声明期间获得数组类型的rvalue?

c++ arrays rvalue lvalue lvalue-to-rvalue

9
推荐指数
2
解决办法
3030
查看次数

对于无符号值的无符号字符类型,左值到右值转换的标准中特殊语言的意义何在

在C++ 14标准(n3797)中,左值转换的左值部分如下所示(强调我的):

4.1左值 - 右值 - 转换[conv.lval]

  1. T可以将非函数非数组类型的glvalue(3.10)转换为prvalue.如果T是不完整类型,则需要进行此转换的程序格式不正确.如果T是非类类型,则prvalue的类型是cv-nonqualified version T.否则prvalue的类型是T.

  2. 当在未评估的操作数或其子表达式中发生左值到右值转换时(第5条),不访问引用对象中包含的值.在所有其他情况下,转换结果根据以下规则确定:

    • 如果T是(可能是cv限定的)std::nullptr_t则结果是空指针常量.
    • 否则,如果T有类类型,则转换复制 - T从glvalue 初始化一个临时类型,转换的结果是临时的prvalue.
    • 否则,如果glvalue引用的对象包含无效指针值,则行为是实现定义的.
    • 否则,如果T是(可能是cv限定的)无符号字符类型,并且glvalue引用的对象包含不确定的值,并且该对象没有自动存储持续时间,或者glvalue是一元运算&符的操作数,或者它是绑定到引用,结果是一个未指定的值.
    • 否则,如果glvalue引用的对象具有不确定的值,则行为未定义.
    • 否则,glvalue指示的对象是prvalue结果.
  3. [ 注:另见3.10]

这一段有什么意义(粗体)?

如果此段落不在此处,那么它适用的情况将导致未定义的行为.通常,我希望unsigned char在具有不确定值时访问值会导致未定义的行为.但是,这一段意味着

  • 如果我实际上没有访问字符值,即我立即将其传递给&或将其绑定到引用,或者
  • 如果unsigned char没有自动存储时间,

然后转换产生一个未指定的值,而不是未定义的行为.

我是否正确地得出这个程序的结论:

#include <new>
#include <iostream>

// using T = int;
using T = unsigned char;

int main() {
  T * array = new T[500];
  for …
Run Code Online (Sandbox Code Playgroud)

c++ undefined-behavior language-lawyer lvalue-to-rvalue c++14

8
推荐指数
1
解决办法
168
查看次数