Is it possible to create an object of type unexpected
for a std::expected<void, void>
?
Here's a simple example.
#include <expected>
[[nodiscard]]
std::expected<void, void> do_logic() {
return std::unexpected<void>();
}
This does not compile, at least not with gcc-14.
error: no matching function for call to ‘std::unexpected<void>::unexpected()’
I am surprised that this code does not compile because the following does compile:
#include <expected>
[[nodiscard]]
std::expected<void, int> do_logic() {
return std::unexpected<int>(-1);
}
Is there a way to make it work with <void, void>
?
Intended Use
const auto result = do_logic();
if(result.has_value()) {
// success case
}
else {
// error case
}
Is it possible to create an object of type unexpected
for a std::expected<void, void>
?
Here's a simple example.
#include <expected>
[[nodiscard]]
std::expected<void, void> do_logic() {
return std::unexpected<void>();
}
This does not compile, at least not with gcc-14.
error: no matching function for call to ‘std::unexpected<void>::unexpected()’
I am surprised that this code does not compile because the following does compile:
#include <expected>
[[nodiscard]]
std::expected<void, int> do_logic() {
return std::unexpected<int>(-1);
}
Is there a way to make it work with <void, void>
?
Intended Use
const auto result = do_logic();
if(result.has_value()) {
// success case
}
else {
// error case
}
Share
Improve this question
edited Mar 16 at 14:25
user2138149
asked Mar 14 at 22:23
user2138149user2138149
17.7k30 gold badges149 silver badges296 bronze badges
11
|
Show 6 more comments
1 Answer
Reset to default 1You can't form the type std::unexpected<void>
because
A program that instantiates the definition of
unexpected
for a non-object type, an array type, a specialization ofunexpected
, or a cv-qualified type is ill-formed.
https://eel.is/c++draft/expected.un.general#2
and
void
is not an object type because
An object type is a (possibly cv-qualified) type that is not a function type, not a reference type, and not cv
void
.
https://eel.is/c++draft/basic.types#general-8
std::expected
inherits the requirements of std::unexpected
, therefore std::expected<?, void>
is prohibited.
A program that instantiates the definition of the template
expected<T, E>
with a type for theE
parameter that is not a valid template argument forunexpected
is ill-formed.
https://eel.is/c++draft/expected.void#general-2
Since you can't form the type std::expected<void, void>
, it is pointless to try to find return expressions compatible with that type.
std::monostate
in<variant>
(or<utility>
in C++26), which you can use instd::expected<void, std::monostate>
. It's like void in many respects, but it is instantiatable because it is a complete type. (It's much like an empty-tuplestd::tuple<>
or empty structstruct empty {};
or even single-valuedstd::nullptr_t
, albeit it with some nicer properties and semantics than those others provide.) – Eljay Commented Mar 15 at 8:36bool
? – PiotrNycz Commented Mar 15 at 18:01std::expected
resolves this design problem. – user2138149 Commented Mar 16 at 14:24std::expected<void,void>
- represents only one bit of information - ok/not-ok -- likebool
. en.wikipedia./wiki/KISS_principle – PiotrNycz Commented Mar 16 at 15:38