Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/131.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ std::可选:简单值和ref限定值之间的有效差异()_C++_C++17_Stdoptional - Fatal编程技术网

C++ std::可选:简单值和ref限定值之间的有效差异()

C++ std::可选:简单值和ref限定值之间的有效差异(),c++,c++17,stdoptional,C++,C++17,Stdoptional,这是一个学术问题。std::optional类型有一个T&&value()&&方法。我有以下定义: class A { ... }; void f(A &&a); 以及以下节目: std::optional<A> optA; optA = A(1337); f(std::move(optA).value()); // OPTION 1 f(std::move(optA.value())); // OPTION 2 std::cout << optA.ha

这是一个学术问题。
std::optional
类型有一个
T&&value()&&
方法。我有以下定义:

class A { ... };
void f(A &&a);
以及以下节目:

std::optional<A> optA;
optA = A(1337);
f(std::move(optA).value()); // OPTION 1
f(std::move(optA.value())); // OPTION 2
std::cout << optA.has_value() << std::endl;
std::可选optA;
optA=A(1337);
f(std::move(optA).value());//选择1
f(std::move(optA.value());//选择2

std::cout在
std::move(optA.value()
std::move(optA.value())
之间没有区别
value()
只返回一个引用所包含值的glvalue,您可以让
value()
返回一个左值,然后通过
std::move
将其转换为xvalue,或者您可以先调用
std::move
并让
value()
立即给您一个xvalue(实际上,从lvalue到xvalue的转换将发生在
value()
方法本身的某个地方)。在这种简单的情况下,ref限定的重载显然不是很有用,但是当通过转发引用
O&&O
传递可选值,并且您希望
std::forward(O).value()
传递到“做正确的事”。

std::move(optA).value()
std::move(optA.value())
value()
只返回一个引用包含值的glvalue,您可以使用
value()
返回一个左值,然后通过
std::move
将其转换为xvalue,或者您可以先调用
std::move
,让
value()
立即给您一个xvalue(实际上,从左值到xvalue的转换将发生在
value()
方法本身的某个地方)。在这种简单的情况下,ref限定的重载显然不是很有用,但是当通过转发引用
O&&O
传递可选内容,并且您希望
std::forward(O).value()
来“做正确的事情”时,它可能会很有用

您“移动了”
optA
,但这并不意味着您更改了它。通常,您不应该在它“移出”后使用值,因为它处于有效但不确定的状态。
std::move
只是一个类型转换(与
静态转换(optA)
完全相同).Moving构造函数未被调用,因为未创建
std::optional
的新实例。因此
具有\u值
返回
true

在这种情况下,确实调用了
T&&value()&&

f(std::move(optA.value())); // OPTION 2
这里不调用
T&&value()&&
,因为
optA
不是
&
。所以您得到
A&
,并通过
std::move
将其强制转换为
A&&
,然后传递到
f
,它可能不起任何作用。
optA
没有更改,但仍然报告它包含值

您“移动了”
optA
,但这并不意味着您更改了它。通常,您不应该在它“移出”后使用值,因为它处于有效但不确定的状态。
std::move
只是一个类型转换(与
静态转换(optA)
完全相同).Moving构造函数未被调用,因为未创建
std::optional
的新实例。因此
具有\u值
返回
true

在这种情况下,确实调用了
T&&value()&&

f(std::move(optA.value())); // OPTION 2
这里不调用
T&&value()&&
,因为
optA
不是
&
。所以您得到
A&
,并通过
std::move
将其强制转换为
A&&
,然后传递到
f
,它可能不起任何作用。
optA
没有更改,但仍然报告它包含值

是否存在value()&&与std::move和value()不同的情况

考虑以下几点:

optional<A> func() {...}

void f(optional<A> opt) {...}
void g(A a) {...}

f(func());
g(func().value());
h
的参数是由move初始化的。为什么?因为如果访问prvalue的成员子对象,结果表达式是xvalue,因此可以在不显式使用
std::move
的情况下进行移动

optional
&&
构造函数确保
value
以同样的方式工作。如果在prvalue临时调用它,那么它将返回一个xvalue,无需显式的
std::move
调用就可以从中移动它。因此在原始情况下,
g
的参数是通过move初始化的,这与它将要做的完全一样如果它正在访问prvalue的成员子对象,则具有

是否存在value()&&与std::move和value()不同的情况

考虑以下几点:

optional<A> func() {...}

void f(optional<A> opt) {...}
void g(A a) {...}

f(func());
g(func().value());
h
的参数是由move初始化的。为什么?因为如果访问prvalue的成员子对象,结果表达式是xvalue,因此可以在不显式使用
std::move
的情况下进行移动


optional
&&
构造函数确保
value
以同样的方式工作。如果在prvalue临时调用它,那么它将返回一个xvalue,无需显式的
std::move
调用就可以从中移动它。因此在原始情况下,
g
的参数是通过move初始化的,这与它将要做的完全一样如果它正在访问一个prvalue的成员子对象,那么它就有了。

我假设两个版本是相同的,但是,Nicol Bolas的答案看起来很有趣

假设它们都产生右值,代码也不重要,我们没有理由忽略可读性

  std::move(optA).value()
这表明您移动了变量,并且依赖于类的编写器来提供正确的重载。如果缺少,您可能会错过

一些过梁也认为这是一个变量,不应该再碰它了,这会阻止你在移动后使用它

std::move(optA.value())

但是,它将返回值转换为rValuy。我主要把这个代码看作是一个bug。函数要么按值返回(要么const引用),然后我们写入许多代码。否则,函数返回一个LValk,并且可能破坏了