Date: Mon, 21 Aug 2023 15:16:41 +0100
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.
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.
Received on 2023-08-21 14:16:44