When I use std::expected I found very verbose handling the pass through of the error over the chain of the calls. To simplify the life to the developer, rust has the ‘?’ (error propagation) operator.
I tried to mimic this using a macro, returns immediately in case of error, or pass the value otherwise.
For example
#include <stdio.h>
#include <expected>
#define TRY(x) __extension__({
auto tmp = x;
if (!tmp)
return std::unexpected(tmp.error());
tmp.value();
})
std::expected<int, bool> effe(bool err) {
if (!err)
return std::unexpected(false);
return 5;
}
std::expected<int, bool> effe2(bool err) {
auto r = TRY(effe(err));
return r + 3;
}
std::expected<int, bool> effe3(bool err) {
auto r = effe(err);
if (!r)
return std::unexpected(r.error());
return *r + 3;
}
int main() {
auto r = effe2(false);
if (!r)
printf("Error returnedn");
else
printf("r=%dn", *r);
r = effe2(true);
if (!r)
printf("Error returnedn");
else
printf("r=%dn", *r);
r = effe3(false);
if (!r)
printf("Error returnedn");
else
printf("r=%dn", *r);
return 0;
}
effe2()
uses the macro, so you have to think only to use the value. In effe3()
the developer has to manage explicitly the error, returning unexpected
.
Now my question is: apart that the fact the “braced-groups within expressions” is a GCC/CLANG extension, do you see any other downside to this approach ?