从返回 std::optional of std::vector 的函数中获取结果到调用方

Get result into the caller from a function returning std::optional of std::vector

本文关键字:std 结果 获取 调用 optional 返回 of vector 函数      更新时间:2023-10-16

我正在尝试使用像std::vector这样的容器来操纵std::optional

我从下面的代码开始:

#include <iostream>
#include <vector>
#include <string>
#include <optional>
using namespace std;
using optional_vecs = std::optional<std::vector<std::string>>;
optional_vecs returnStrings()
{
optional_vecs myVect(std::in_place); 
myVect->emplace_back("Name");
return myVect;
}
int main()
{
for (auto e : returnStrings().value())
std::cout << e << " ";
return 0;
}

这里的问题是我在输出中什么也没得到:我想这是因为std::optional::value返回一个引用,就像在我的例子中它是对临时的引用一样。

因此,为了解决,我尝试使用如下所示std::reference_wrapper

using optional_vecs = std::optional<std::reference_wrapper<std::vector<std::string>>>;
optional_vecs returnStrings()
{
optional_vecs myVect; 
myVect->get().emplace_back("Name");
return myVect;
}

现在我遇到了崩溃和错误:

  • 尝试添加字符串"name"时发生崩溃。
  • 错误是当我尝试使用for-range循环说the range for loop requires a suitable "begin" function and none was found.

下面的代码有效,但我不喜欢声明一个变量,然后调用 Value((:

int main()
{
auto result = returnStrings();
for (auto e : result.value())
std::cout << e << " ";
return 0;
}

那么我怎么能返回一个 std::optional,在functionName().Value()的方式上拿着一个std::vector.

在前两种情况下,您的问题是,由于returnStrings()返回一个临时的,除非您实际捕获它返回的内容,否则 for 循环不会延长其生命周期。 捕获result.value()对您没有任何好处,因为它不会延长returnStrings()的使用寿命。

那么我怎么能以functionName().Value()的方式返回一个 std::optional 持有 std::vector .

你必须捕捉functionName()的回报. 您可以执行所做的事情,或者在 C++20 中,您可以使用 ranged 的新init-语句版本,该版本是为此类情况构建的,看起来像

for (auto&& opt_vec =  returnStrings(); auto e : opt_vec.value())
std::cout << e << " ";

不幸的是,您必须使用后一种结构。

optional对象负责拥有vector。C++不会递归地将生存期延长到拥有引用对象的对象,因此,如果该拥有对象被销毁(因为它是临时的(,引用的对象也会被销毁。

不过我要指出的一件事是:至少就GCC而言,这是有效的代码:

int main()
{
for (auto ret = returnStrings(); auto e : ret.value())
std::cout << e << " ";
return 0;
}

更改为optional<reference_wrapper<vector>>也不起作用,因为原始returnStrings函数返回一个右值,这意味着如果不是用于复制省略,该原始对象将被移动分配,然后也被破坏。

因此,如果函数返回optional<vector>至关重要,那么您的for循环将需要具有正确初始化可选对象本身的东西。

您需要使用std::optional包装器,就像使用它的模板底层类型一样。在您的情况下,它std::string,这应该有效。

#include <iostream>
#include <vector>
#include <string>
#include <optional>
using namespace std;
using optional_vecs = std::optional<std::vector<std::string>>;
optional_vecs returnStrings()
{
std::vector<std::string> myVect{};
myVect.emplace_back("Name");
return std::optional{ myVect };
}
int main()
{
auto stringsOpt = returnStrings();
if (stringsOpt) {
for (auto& e : *stringsOpt)
std::cout << e << " ";
}
return 0;
}

此代码实际上适用于 GCC。

PS:令人惊讶的是,您的源代码无法在 MSVC 上编译。