passing boost::optional lvalue as a reference to a function

2.9k views Asked by At

Can you somehow pass boost::optional lvalue as a reference into a function which changes the value? Something like this (http://coliru.stacked-crooked.com/a/f77d3b095af3d66b):

#include <iostream>

#include <boost/optional.hpp>

void foo(int& x)
{
    x = 3;
}

int main() {
    boost::optional<int> y;
    foo(*y);
    std::cout << *y << std::endl;
}

which doesn't work, unsurprisingly.

The function needs to use standard type as the output argument tho (e.g. int& x). I hope I am explaining this correctly. I am asking about general possibility of my intention.

2

There are 2 answers

2
Zilicon On BEST ANSWER

Yes. you just have to initialize the optional like your compilation error suggests:

boost::optional::reference_type boost::optional::get() [with T = int; boost::optional::reference_type = int&]: Assertion `this->is_initialized()' failed.

This works & prints 3:

#include <iostream>
#include <boost/optional.hpp>

void foo(int& x)
{
    x = 3;
}

int main() {
    boost::optional<int> y = 2;
    foo(*y);
    std::cout << *y << std::endl;
}

An important remark noted by the op, is that even if the initialization value is not known in compile time, boost will anyway assert the optional's state (on operator* or on get()), which means that if the optional is not set (boost::none) the application will crash.

So one can either initialize with a valid-value-containing optional (non boost::none), or pass optional<int>&.

0
bradgonesurfing On

You want to be very careful here. If you swap boost::optional for std::optional then std::optional does not protect you with the compiler. See that with std::optional i have not initialized. There is no compiler error. I am allowed to write to the optional but the optional is still not considered initialized ie (bool)y == false

#include <iostream>
#include <boost/optional.hpp>
#include <boost/optional/optional_io.hpp>
#include <optional>

void foo(int& x)
{
    x = 3;
}

int main() {
    {
      boost::optional<int> y = 2;
      foo(*y);
      std::cout << *y << " " << !!y << std::endl;
    }

    {
      std::optional<int> y;
      foo(*y);
      std::cout << *y << " " << !!y << std::endl;
    }
}

output is

3 1
3 0

http://coliru.stacked-crooked.com/a/a169e7c43052a206