我希望我的函數返回成功的指示或描述失敗性質的對象。我通常會爲此使用異常,但我被告知不要將它們用於通用代碼路徑,並且由於各種原因,這組函數可能會經常失敗。如何從函數中返回成功或錯誤對象?
我的想法是使用C++ 17的std::optional
,因爲我不必在不需要時返回完整的錯誤對象。因此,對於可選的,如果函數不成功,則返回錯誤對象,否則可選項爲空。與此相關的問題是它逆轉了對返回值的期望(即true
通常表示成功而非失敗)。
我可以讓人們使用is_success
功能,這將是這樣被使用,假設Error
是我的錯誤類:
auto result = do_stuff();
if (!is_success(result)) {
Error err = *result;
// ...
}
還是會因此類更爲強勁?
class MaybeError {
std::optional<Error> _error;
public:
MaybeError(const Error& error) : _error(error) {}
constexpr MaybeError() : _error({}) {}
explicit operator bool const() {
return !(_error.operator bool());
}
constexpr bool has_error() const {
return !(_error.has_value());
}
constexpr Error& error() & { return _error.value(); }
constexpr const Error & error() const & { return _error.value(); }
constexpr Error&& error() && { return std::move(_error.value()); }
constexpr const Error&& error() const && { return std::move(_error.value()); }
constexpr const Error* operator->() const { return _error.operator->(); }
constexpr Error* operator->() { return _error.operator->(); }
constexpr const Error& operator*() const& { return _error.operator*(); }
constexpr Error& operator*() & { return _error.operator*(); }
constexpr const Error&& operator*() const&& { return std::move(_error.operator*()); }
constexpr Error&& operator*() && { return std::move(_error.operator*()); }
};
這同樣可以使用在第一個例子:
auto result = do_stuff();
if (!result) {
Error err = *result;
// ...
}
什麼是最好的選擇嗎?我是否以正確的方式去做這件事?
編輯要明確的是,do_stuff
功能被呼叫如果成功,不返回的對象。如果它總是成功沒有錯誤,它只是void do_stuff()
。
編輯2在評論克里斯蒂安·哈克建議使用一個簡單的結構較不超工程解決方案。
struct MaybeError {
std::optional<Error> error;
};
這將是既簡單,解決我的擔心,人們會期望通過功能擺明,這是所要檢測的錯誤情況返回如果成功的話屬實。例如:
auto result = do_stuff();
if (result.error) {
Error e = *t.error;
// ...
}
這看起來非常複雜,當使用異常時會更清晰和更簡單,並且涉及更少的代碼。 –
我很樂意使用例外,但不幸的是,我的老闆對這個問題有着強烈的感受。 – ChrisD
他是個白癡。良好C++代碼中的異常不是可選的。 –