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

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

我正在尝试使用像 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 return 一个引用,在我的例子中它是一个临时的引用。

所以为了解决这个问题,我尝试使用 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;
}

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

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

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

    return 0;
}

那我怎么能return一个std::optional拿着一个std::vector挡着functionName().Value().

您需要在使用 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。

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

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

的生命周期

So how could I return an std::optional holding a std::vector in the way functionName().Value().

您必须捕获 functionName() 的 return。你可以做你所做的,或者在 C++20 中,你可以使用新的 init-statement 版本的范围,它是为这样的情况构建的,看起来像

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

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

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

有一件事我要指出:至少就 GCC 而言,this is valid code:

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

    return 0;
}

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

因此,如果函数 return 和 optional<vector> 非常重要,那么您的 for 循环将需要一些东西来正确初始化可选对象本身。