Reputation: 3233
The following code:
#include <chrono>
#include <expected>
#include <stdexcept>
#include <string>
#include <thread>
#include <utility>
using namespace std::literals;
class Resource {
Resource() { /* some setup, might raise */ }
public:
static std::expected<Resource, std::string> tryCreate() noexcept {
try {
return Resource();
} catch (const std::runtime_error& exc) {
return std::unexpected(exc.what());
}
}
static const Resource create() noexcept {
while (true) {
const auto resource{Resource::tryCreate()};
if (resource.has_value()) return resource.value(); // <-- this is no good.
else std::this_thread::sleep_for(1s);
}
}
Resource(const Resource&) = delete;
Resource(Resource&& other) noexcept {}
Resource& operator=(const Resource&) = delete;
Resource& operator=(Resource&& other) noexcept { return *this; }
~Resource() { /* some cleanup */ }
void use() const noexcept {}
};
int main() noexcept {
const auto resource{Resource::create()};
resource.use();
}
... refuses to compile with the error:
<source>:25:42: error: call to deleted constructor of 'const Resource'
25 | if (resource.has_value()) return resource.value();
| ^~~~~~~~~~~~~~~~
<source>:29:3: note: 'Resource' has been explicitly marked deleted here
29 | Resource(const Resource&) = delete;
| ^
1 error generated.
Compiler returned: 1
I don't see any explanation on cppreference that move-only types aren't allowed, and I'm not immediately able to find anyone else having a similar problem while searching the internet, (though I'm still new to this, so it's probable my C++ google-fu is inadequate). I think it might be something to do with "copy elision" but truly I'm quite lost.
Is it not possible to use a move-only type with std::expected
? If it is, how can I modify my example code such that it works (without defining copy constructors)?
godbolt - fails on Clang with -std=c++23, but I'm experiencing similar with GCC 14.2.1, again with -std=c++23.
Upvotes: 4
Views: 87
Reputation: 72063
There is an rvalue overload of value()
which returns an rvalue reference. So you can write return std::move(resource).value();
. But for that, the local resource
variable must not be const
.
Upvotes: 5