I have a much simpler set of requirements and do not need much of variant's machinery. I also do not want to depend on boost if I can help it.
I need to store either an arbitrary type known at compile time (that may be void
). It is either move constructable or copy constructable, and if either of those throw, it is permissible for the contained value to be undefined.
Instead of this value, it may also either contain an ::std::exception_ptr
or an ::std::error_code
.
::boost::variant<T, ::std::exception_ptr, ::std::error_code>
would work if T
is allowed to be void. Except that ::boost::variant
provides the 'never-empty guarantee' which I don't actually need in this instance. And, if I understand how it works correctly, it's not very compatible with types that can be moved but not copied.
Right now I'm writing a lot of duplicated code that I shouldn't have to be writing to handle each of these types separately. I'm also storing a copy of an object of each type and flag values saying which is relevant. Lastly, void
gives the whole system conniptions and is requiring I write specializations all over the place.
Is there a better way?
Here's a simplified example of what I have. This is basically a class designed to hold a result for transmission to another thread, sort of like a future:
template <typename ResultType>
class stored_result {
public:
stored_result() : is_val_(false), is_err_(false), is_exception_(false) { }
void set_bad_result(::std::error err) {
is_err_ = true;
error_ = ::std::move(err);
}
void set_bad_result(::std::exception_ptr exception) {
is_exception_ = true;
exception_ = ::std::move(exception);
}
void set_result(ResultType res) {
is_val_ = true;
val_ = ::std::move(res);
}
ResultType result() {
if (is_val_) {
is_val_ = false;
return ::std::move(val_);
} else if (is_exception_) {
is_exception_ = false;
::std::rethrow_exception(::std::move(exception_));
} else if (is_error_) {
is_error_ = false;
throw ::std::system_error(error_);
} else {
throw ::std::runtime_error("Asked for result when there was none.");
}
}
private:
bool is_val_, is_err_, is_exception_;
T val_;
::std::exception_ptr exception_;
::std::error_code error_;
};