Search code examples
c++copy-elisionstdoptional

Can I copy-elide an immovable & uncopyable function result into an optional?


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?


Solution

  • 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});