I want to store a non-trivial type that is immovable and not copyable in an std::optional
. However the object is constructed by a free function. (example)
struct Foo {
Foo();
Foo(Foo const&) = delete;
Foo(Foo&&) = delete;
Foo& operator=(Foo const&) = delete; // added for completeness
Foo& operator=(Foo&&) = delete; // added for completeness
~Foo();
};
Foo foo();
Without changing Foo
or foo()
;
Thanks to copy elision, I can already do this:
Foo f1 = foo();
And this also compiles, because std::optional
only requires the stored type to be destructible:
std::optional<Foo> f2;
f2.emplace();
But I cannot fill f2
with a function result:
f2 = foo(); // no
f2.emplace(foo()); // no
Obviously, because this would require copies or moves of Foo
. This is likely impossible, but have I overlooked something?
CodePudding user response:
You can make a class where a conversion operator calls the function and returns the result. Since the conversion operator will create a prvalue, you don't need the type to be copyable/movable:
template<typename F>
struct call_wrapper {
F&& f;
constexpr operator decltype(auto)() && {
return static_cast<F&&>(f)();
}
};
template<typename F>
call_wrapper(F&&) -> call_wrapper<F>;
std::optional<Foo> f2;
f2.emplace(call_wrapper{foo});
CodePudding user response:
Not sure if this fits your requirement of not modifying Foo
or foo
, but you can use a Bar
wrapper that default initializes a Foo
member by calling foo
:
#include <optional>
namespace {
struct Foo {
Foo() = default;
Foo(Foo const&) = delete;
Foo(Foo&&) = delete;
Foo& operator=(Foo const&) = delete;
Foo& operator=(Foo&&) = delete;
~Foo() {}
};
Foo foo() { return {}; }
struct Bar {
Foo f = foo();
};
}
int main() {
std::optional<Bar> f3;
f3.emplace();
}
I think the answer to the title is No. You cannot copy or move a Foo
into an optional
, but via the wrapper you can construct it in place.