Summary
Explore using std::expected<T, E> (C++23) as the return type for pop() to provide richer error information and a more ergonomic API.
Motivation
The current pop(T& value) API uses an output parameter and returns bool. While simple and zero-overhead, it gives no information about why the operation failed and requires an output parameter rather than a natural return value.
std::expected enables:
// Current
T value;
if (!queue.pop(value)) { /* handle empty */ }
// With std::expected
auto result = queue.pop();
if (result) {
process(*result);
} else if (result.error() == QueueError::Empty) {
// handle empty
}
Proposed API
enum class QueueError { Empty, Full };
// pop returns value or error
[[nodiscard]] std::expected<T, QueueError> pop();
// push could also return error info
[[nodiscard]] std::expected<void, QueueError> push(const T& value);
[[nodiscard]] std::expected<void, QueueError> push(T&& value);
Monadic chaining (C++23)
queue.pop()
.transform([](T v) { return process(v); })
.or_else([](QueueError e) {
log("queue empty");
return std::expected<Result, QueueError>{};
});
Trade-offs
| Aspect |
bool + out-param |
std::expected |
| Overhead |
Zero |
Zero (same layout) |
| Error info |
None |
Full error type |
| Ergonomics |
Requires out-param |
Natural return value |
| C++ version |
C++11 |
C++23 |
| Familiarity |
High |
Lower (newer) |
Considerations
- Zero runtime overhead —
std::expected is as cheap as std::optional for the success path
- Backwards-incompatible API change — would require a major version bump
- Could offer both APIs: keep
pop(T&) and add try_pop() returning std::expected
- Useful if error types expand (e.g.
Closed when a close() method is added)
References
Summary
Explore using
std::expected<T, E>(C++23) as the return type forpop()to provide richer error information and a more ergonomic API.Motivation
The current
pop(T& value)API uses an output parameter and returnsbool. While simple and zero-overhead, it gives no information about why the operation failed and requires an output parameter rather than a natural return value.std::expectedenables:Proposed API
Monadic chaining (C++23)
queue.pop() .transform([](T v) { return process(v); }) .or_else([](QueueError e) { log("queue empty"); return std::expected<Result, QueueError>{}; });Trade-offs
Considerations
std::expectedis as cheap asstd::optionalfor the success pathpop(T&)and addtry_pop()returningstd::expectedClosedwhen aclose()method is added)References