admin管理员组文章数量:1431244
I modeled a function that returns an instance of an std::expected<void, Error>
- I told myself "I can use a new standard so I will design my library accordingly" - and I was very positive to have nice and concrete error handling. Now it turns out, that all the monadic operations on the std::expected
only work on non-void items. Even though there is a specialization for void, the monadic operations are not available.
I understand that or_else
needs to return the value - but there is a specialization for void, so why should this not work?
std::expected<void, Error> fun (int);
fun (19).and_then ([]() { doSomething(); }).or_else ([] (Error e) { std::println ("Uh oh error.."); });
This yields:
/usr/include/c++/14.2.1/expected:1586:37: error: static assertion failed
1586 | static_assert(__expected::__is_expected<_Up>);
| ~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~
/usr/include/c++/14.2.1/expected:1586:37: note: ‘std::__expected::__is_expected<void>’ evaluates to false
/usr/include/c++/14.2.1/expected:1587:25: error: ‘std::remove_cvref<void>::type’ {aka ‘void’} is not a class, struct, or union type
1587 | static_assert(is_same_v<typename _Up::error_type, _Er>);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/14.2.1/expected:1592:20: error: expression list treated as compound expression in functional cast [-fpermissive]
1592 | return _Up(unexpect, std::move(_M_unex));
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/david/tests/cpp/src/expect.cpp: In function ‘int main()’:
/home/david/tests/cpp/src/expect.cpp:49:26: error: invalid use of ‘void’
What's the problem here? Is this feature only half done (so the standard is incomplete) or am I misunderstanding its point?
I modeled a function that returns an instance of an std::expected<void, Error>
- I told myself "I can use a new standard so I will design my library accordingly" - and I was very positive to have nice and concrete error handling. Now it turns out, that all the monadic operations on the std::expected
only work on non-void items. Even though there is a specialization for void, the monadic operations are not available.
I understand that or_else
needs to return the value - but there is a specialization for void, so why should this not work?
std::expected<void, Error> fun (int);
fun (19).and_then ([]() { doSomething(); }).or_else ([] (Error e) { std::println ("Uh oh error.."); });
This yields:
/usr/include/c++/14.2.1/expected:1586:37: error: static assertion failed
1586 | static_assert(__expected::__is_expected<_Up>);
| ~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~
/usr/include/c++/14.2.1/expected:1586:37: note: ‘std::__expected::__is_expected<void>’ evaluates to false
/usr/include/c++/14.2.1/expected:1587:25: error: ‘std::remove_cvref<void>::type’ {aka ‘void’} is not a class, struct, or union type
1587 | static_assert(is_same_v<typename _Up::error_type, _Er>);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/14.2.1/expected:1592:20: error: expression list treated as compound expression in functional cast [-fpermissive]
1592 | return _Up(unexpect, std::move(_M_unex));
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/david/tests/cpp/src/expect.cpp: In function ‘int main()’:
/home/david/tests/cpp/src/expect.cpp:49:26: error: invalid use of ‘void’
What's the problem here? Is this feature only half done (so the standard is incomplete) or am I misunderstanding its point?
Share Improve this question asked Nov 19, 2024 at 9:04 DavidDavid 3971 gold badge3 silver badges12 bronze badges 3 |2 Answers
Reset to default 17The problem is that the callable to and_then
and or_else
needs to return a specialization of std::expected
for chaining to work. Your lambdas do not.
If fun
were to return an unexpected (an error), and_then
won't call your callable, but it will need to forward the error into the same sort of unexpected
type that the lambda returns. So the lambda for and_then
should return std::unexpected<..., Error>
. You can choose what ever "expected" type you want the lambda to return, just as long as it's the same Error
type. You can stick to void
of course.
fun (19).and_then ([]() { doSomething(); return std::expected<void, Error>(); })
Conversly, the callbale to or_else
can choose a different error type, but needs to preserve the expected type in its returned std::expected
specialization. But all in all, the same treatment should work.
fun (19).and_then ([]() {
doSomething();
return std::expected<void, Error>();
}).or_else ([] (Error e) {
std::println ("Uh oh error..");
return std::expected<void, Error>();
});
Note I opted to have or_else
swallow the error and return an std::expected
with a value. You could choose to forward the error, of course.
...
.or_else ([] (Error e) {
std::println ("Uh oh error..");
return std::expected<void, Error>(std::unexpect, e);
});
Although this is already answered by another answer to this question, let me add that transform
and transform_error
is probably what you expected for the library function instead.
fun(19).transform([]() { doSomething(); }).transform_error([](Error e) {
std::println("Uh oh error..");
return e;
});
There is a difference between monad and functor.
and_then
andor_else
behaves monadically.and_then
take in a functionT -> std::expected<U, E>
and transform fromstd::expected<T, E>
tostd::expected<U, E>
transform
andtransform_error
behave like functor.transform
take in a functionT -> U
and transform fromstd::expected<T, E>
tostd::expected<U, E>
.
It is interesting that the transform_error
cannot have U = void
if T
is not void based on my testing. The monadic variant is more expressive as you can be returning a different result, for example returning the unexpected variant whenever something goes wrong inside and_then
instead.
本文标签: cWhy are there no monadic operations in stdexpectedltvoidErrorgtStack Overflow
版权声明:本文标题:c++ - Why are there no monadic operations in std::expected<void, Error> - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1745571337a2664065.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
and_then
andor_else
needs to return a specialization ofstd::expected
for chaining to work. Your lambdas do not. – StoryTeller - Unslander Monica Commented Nov 19, 2024 at 9:10and_then
return? – David Commented Nov 19, 2024 at 9:27