Search code examples
c++functionc++17unique-ptrstdoptional

How to pass std::optional struct that contains std::unique_ptr to a function?


I am learning how to use std::optional, and I am having trouble passing a std::optional<Type> parameter to a function, since Type contains within it a std::unique_ptr, which prevents the call.

What is the correct way to pass such a variable (std::optional<Type>) to a function?

Here is a code snippet that easily reproduces the problem:

#include <iostream>
#include <optional>
#include <memory>
using namespace std;

struct myStruct
{
    std::unique_ptr<int> a;
};

int func(const myStruct& val, std::optional<myStruct> opt)
{
    if (opt.has_value())
    {
        return *(opt.value().a);
    }
    else 
    {
        return *(val.a);
    }
}

int main()
{
    cout << "Hello World";
    myStruct val;
    val.a = std::make_unique<int>(5);
    std::optional<myStruct> opt = std::nullopt;
    myStruct temp;
    temp.a = std::make_unique<int>(10);
    opt = std::move(temp);
    std::cout << "result is " << func(val, opt) << std::endl;
    return 0;
}

The error I see for the code above:

main.cpp:35:47: error: use of deleted function ‘std::optional::optional(const std::optional&)’
     std::cout << "result is " << func(val, opt) << std::endl;
                                               ^
In file included from main.cpp:10:0:
/usr/include/c++/7/optional:453:11: note: ‘std::optional::optional(const std::optional&)’ is implicitly deleted because the default definition would be ill-formed:
     class optional
           ^~~~~~~~
/usr/include/c++/7/optional:453:11: error: use of deleted function ‘constexpr std::_Enable_copy_move::_Enable_copy_move(const std::_Enable_copy_move&) [with _Tag = std::optional]’
In file included from /usr/include/c++/7/optional:43:0,
                 from main.cpp:10:
/usr/include/c++/7/bits/enable_special_members.h:157:15: note: declared here
     constexpr _Enable_copy_move(_Enable_copy_move const&) noexcept  = delete;

Solution

  • Your myStruct is indirectly only movable (non-copyable), because of the member std::unique_ptr<int> a;, which is also by default non-copyable (only move is allowed).

    Therefore the optional variable opt (which contains the struct myStruct) is also indirectly only movable. However, in your function func you are trying to pass opt by value, which in effect tries to copy the underlying struct and hence the compiler error.

    You need to pass opt by const ref, as you are not modifying opt anyway.

    int func(const myStruct& val, const std::optional<myStruct>& opt)
    //                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    {
       // ..code
    }
    

    See live