Получить результат в вызывающую функцию из функции, возвращающей std :: option of std :: vector - PullRequest
0 голосов
/ 21 января 2020

Я пытаюсь манипулировать std::optional с помощью контейнера, например std::vector.

Я начал с кода ниже:

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

Теперь у меня есть cra sh и ошибка:

  • cra sh происходит при попытке добавить строку «name».
  • error это когда я пытаюсь использовать for-range l oop, говоря 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 :: опционально, удерживая std::vector в пути functionName().Value().

Ответы [ 3 ]

3 голосов
/ 21 января 2020

Ваша проблема здесь в первых двух случаях состоит в том, что, поскольку returnStrings() возвращает временное значение, for l oop не продлит его жизнь, если вы на самом деле не получите то, что он возвращает. Захват result.value() не принесет вам никакой пользы, поскольку он не продлит время жизни returnStrings().

Так как же я могу вернуть std :: необязательный, содержащий std :: vector в way functionName().Value().

Вы должны захватить возвращение functionName(). Вы можете делать то же, что и вы, или в C ++ 20 вы можете использовать новую версию ранжирования init-Statement , для которой он был построен для подобных случаев и будет выглядеть как

for (auto&& opt_vec =  returnStrings(); auto e : opt_vec.value())
    std::cout << e << " ";
2 голосов
/ 21 января 2020

К сожалению, вы должны использовать последнюю конструкцию.

Объект optional отвечает за владение vector. C ++ не будет рекурсивно продлевать время жизни до объекта, владеющего ссылочным объектом, поэтому, если этот владелец объекта будет уничтожен (каким он будет, потому что он временный), ссылочный объект также будет уничтожен.

Одна вещь, которую я укажет, хотя: по крайней мере, что касается G CC, это действительный код :

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

    return 0;
}

Изменение на optional<reference_wrapper<vector>> также не работает, потому что оригинал returnStrings функция возвращает значение r, означающее, что если бы не исключение копирования, исходный объект был бы назначен для перемещения, а затем также уничтожен.

Так что, если жизненно важно, чтобы функция возвращала optional<vector>, ваш for-l oop должен иметь что-то, что правильно инициализирует сам необязательный объект.

0 голосов
/ 21 января 2020

Вам нужно работать с 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;
}

Этот код на самом деле работает на G CC.

PS: это удивительно, но ваш исходный код не работает скомпилировать на MSV C.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...