2

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;
JeJo
  • 30,635
  • 6
  • 49
  • 88
  • 1
    You're making a copy when it's passed to `func`. Take it by const reference or such. – MicroVirus Jul 17 '21 at 09:12
  • 1
    Wow, a simplified, clear [mcve] of your issue and as the first question, +1 ; it's too rare around here. – Quimby Jul 17 '21 at 09:18
  • On a side note, at least in Java it is discouraged to have `Optional` for parameters as there is already a concept for optional parameters; different overloads. – Yanick Salzmann Jul 17 '21 at 09:37

1 Answers1

5

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

Amin Karbas
  • 562
  • 1
  • 7
  • 16
JeJo
  • 30,635
  • 6
  • 49
  • 88