Reputation: 4027
boost::optional support in_place construction like so:
#include <boost/optional.hpp>
#include <boost/utility/typed_in_place_factory.hpp>
class Foo
{
int a,b;
public:
Foo(int one, int two) : a(one),b(two) {}
};
int main()
{
boost::optional<Foo> fooOpt(boost::in_place<Foo>(1,3));
}
Once we have an initialized fooOpt, is there a way of assigning a new Foo to it without creating a temporary?
Something like :
fooOpt = boost::in_place<Foo>(1,3);
Thanks!
Upvotes: 10
Views: 7594
Reputation: 81926
#include <boost/optional.hpp>
int main() {
boost::optional<int> x;
x = boost::in_place(3);
}
We can also show (via code) that this is building the object in-place by making Foo
inherit from boost::noncopyable
:
#include <boost/optional.hpp>
#include <boost/noncopyable.hpp>
class Foo : boost::noncopyable {
public:
Foo(int one, int two) {}
};
int main() {
boost::optional<Foo> x;
x = boost::in_place(3, 4);
}
Eventually, we will get access to std::optional
. This type will implement an emplace()
method, that will implement in-place construction as well.
#include <optional>
int main() {
std::optional<int> x;
x.emplace(3);
}
In version 1.56.0, boost::optional
will also implement the emplace()
method that I talked about for std::optional. So, let's see that:
#include <boost/optional.hpp>
int main() {
boost::optional<int> x;
x.emplace(3);
}
Upvotes: 13
Reputation: 275385
The documented interface does not support this.
However, if you know that nobody extends boost::optional
, I believe this may be technically valid:
template<typename T, typename... Us>
void emplace_replace( boost::optional<T>& target, Us&&... us ) {
target.~boost::optional<T>();
try {
new (&target) boost::optional<T>( boost::in_place( std::forward<Us>(us)...) );
} catch(...) {
new (&target) boost::optional<T>();
throw;
}
}
Here, we destroy the target
, then reconstruct a new boost::optional<T>
in its place with in-place construction. The try
-catch
construct should make most throw
s during construction safe: if it throws, you end up with an empty optional
.
This naturally behaves differently than operator=
is expected to.
In 1.55 (and maybe earlier?), there is an undocumented operator=
that takes an Expr
which supports boost::in_place
and boost::in_place<T>
. See @sharth's answer for a detailed use.
My quick reading indicates that a typed inplace factory via this method may have insufficient guards:
boost::optional<int> test;
// test = boost::in_place<double>( 3 ); // <-- very dangerous
test = boost::in_place( 3 ); // safe
test = boost::in_place( 3.0 ); // safe
If a type is passed directly to in_place<?>
, it can generate a typed_in_place_factory
, which are dangerous (they make the passed in type, and don't check that it is compatible). So don't pass any types to boost::in_place
.
This (from reading the source) does something similar to my destroy/reconstruct code, except it does it without destroying the entire optional
and just destroys the stored data and makes it uninitialized.
In boost 1.56b1, emplace has been added to boost::optional
. It does something similar to both of the above operations. (via @AkiraTakahashi)
std::optional
proposals I have seen have included a member function .emplace( Us&&... )
that supports emplace replacing directly.
Upvotes: 3
Reputation: 39089
Once you know it's there, you could create an ordinary reference:
optional<Foo> optFoo = ....;
Foo &foo = *optFoo;
foo.x = 3;
foofun(foo);
foo = Foo();
Upvotes: 0