Не прибегая к уродливым макросам, вы можете сократить обработку ошибок в красивом функциональном стиле. Взгляните:
class c_outcome {
public:
bool success;
std::string error;
template<class Fun, class...Args>
c_outcome then(Fun&& fun, Args&&... args) const {
if (success) {
return std::forward<Fun>(fun)(std::forward<Args>(args)...);
} else {
return *this;
}
}
template<class ErrorHandler>
c_outcome except(ErrorHandler&& fun) const {
if (!success) {
std::forward<ErrorHandler>(fun)(error);
}
return *this;
}
};
template<class Fun, class...Args>
c_outcome run(Fun&& fun, Args&&... args) {
return std::forward<Fun>(fun)(std::forward<Args>(args)...);
}
С таким кодом вы можете использовать его следующим образом:
c_outcome do_everything() {
return run(do_sth, a, input, "a")
.then(do_sth, b, input, "b")
.then(do_sth, c, input, "c")
.except(do_sth2);
}
Основным преимуществом этого кода является универсальный c. Он будет обрабатывать почти все типы типов, которые вы можете себе представить.
РЕДАКТИРОВАТЬ: я обновил код, так что теперь его можно использовать как-то рекурсивно для обработки ошибок