0

I am trying to manipulate the std::optional using container like std::vector.

I started by doing the code below :

#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;
}

The problem here is that I get nothing in the output: I guess that because std::optional::value return a reference as in my case it is a reference to a temporary.

So to resolve that I tried to use std::reference_wrapper as below :

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;
}

Now I got a crash and an error :

  • the crash happens when trying to add the string "name".
  • the error is when I try to use the for-range loop saying the range for loop requires a suitable "begin" function and none was found.

The code below works but I don't like to declare a variable and then calli the Value():

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

    return 0;
}

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

4

3 回答 3

3

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

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

您必须捕获functionName(). 你可以做你所做的,或者在 C++20 中你可以使用新的初始化语句版本的 ranged ,它是为这样的情况而构建的,看起来像

for (auto&& opt_vec =  returnStrings(); auto e : opt_vec.value())
    std::cout << e << " ";
于 2020-01-21T18:34:14.290 回答
2

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

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

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

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

    return 0;
}

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

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

于 2020-01-21T18:34:26.053 回答
0

在使用它的模板基础类型时,您需要使用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 上编译。

于 2020-01-21T18:32:53.700 回答