What about: https://godbolt.org/z/1ebe9E3a3
#include <mutex>
#include <optional>

extern std::mutex FuncThatReturnsMutex();

template<class T, class Fn>
void reemplace(std::optional<T>& opt, Fn&& fn)
{
    if (!opt)
        opt.emplace();

    T* buf = std::addressof(*opt);
    buf->~T();
    new (buf) T(fn());
}

int main()
{
    std::optional<std::mutex> om;
    reemplace(om, FuncThatReturnsMutex);
    // om = FuncThatReturnsMutex();
}
Breno G.

On Mon, Aug 21, 2023 at 11:16 AM Frederick Virchanza Gotham via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
The following is currently impossible in C++26:

    extern std::mutex FuncThatReturnsMutex(void);

    int main(void)
    {
        std::optional<std::mutex> om;
        om = FuncThatReturnsMutex();
    }

It's impossible because a mutex must be either copiable or movable in order to assign it to an 'optional'. We have the same problem with 'std::variant', 'std::any', and lots of classes in other libraries like Boost.

Currently we can write constructors and assignment operators that take:
• an Lvalue ref
• an Rvalue ref

What if we had a third kind whose argument must be a prvalue? An implementation of 'optional' would look something like as follows:

template <typename T>
class optional {
    bool bool_has_value = false;
    alignas(T) char unsigned buf[sizeof(T)];
public:
    optional(T ^^arg) : buf(arg)
    {
    
    }

    optional &operator=(T ^^arg) : buf(arg)
    {
        if ( this->bool_has_value )
        {
            static_cast<T*>(static_cast<void*>(&buf))->~T();
            this->bool_has_value = false;
        }

        __emplace;

        this->bool_has_value = true;

        return *this;
    }
};

In the case of the constructor, if 'FuncThatReturnsMutex' throws an exception, then the 'optional' constructor as a whole will throw an exception, so no problem there.

But in the case of the assignment operator, we have a problem if 'FuncThatReturnsMutex' throws, so we need control over when the prvalue gets generated -- and that's why I have the '__emplace' keyword there.
--
Std-Proposals mailing list
Std-Proposals@lists.isocpp.org
https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals