有沒有其他方法可以替代std::optional我不必將result作為引數傳遞給函式的地方。我希望函式不修改它的引數(更純/不可變)。
TL; 博士
問題std::optional似乎是我們丟失了有關錯誤的資訊。該函式回傳一個值或空的東西,因此您無法判斷出了什么問題。
使用 std::optional
std::optional<std::string> doSomething() {
std::string value;
int rc = callApi(value);
if (rc == 0) {
//do some processing on value
return value;
}
return std::nullopt;
}
//calling the function seems much more pure/cleaner than when passing a result parameter.
沒有 std::optional
int doSomething(std::string& result) {
std::string value;
int rc = callApi(value);
if (rc == 0) { //if no error
//do some processing on value and set result = value
result = value;
}
return rc;
}
uj5u.com熱心網友回復:
看起來您正在尋找的是std::expected.
......它實際上已經不在標準中了,但是:
- 您可以閱讀提案的最新版本,P0323 修訂版 10
- 你可以使用它!或者更確切地說,是由才華橫溢的 Sy Brand / TartanLlama 實作的,包括一些我不會介紹的不錯的擴展。
但是——這是什么?
嗯......一言以蔽之:當你想回傳要么一定的價值,或者某種故障/錯誤描述的,你只是模板的,說成T,E,而這些都是模板引數:std::expected<T, E>。因為 T 和 E 是不相交的型別,所以你知道你從函式中得到了哪一個。
這是您的函式,適用于您的 API 似乎具有的錯誤型別:
namespace my_api {
using error_t = int;
enum : error_t { success = 0, invalid_input = 1, /* etc. */ };
} // namespace my_api
std::expected<std::string, my_api::error_t> doSomething() {
std::string value;
my_api::error_t rc = callApi(value);
if (rc != success) { return rc; }
//do some processing on value
return value;
}
當然,my_api命名空間不是我建議的一部分,它只是一個說明,因為您沒有指出您希望如何傳達錯誤。實際上,您甚至可以添加:
namespace my_api {
template <typename T>
using expected = std::expected<T, error_t>;
} // namespace my_api
然后你的函式簽名變成:
my_api::expected<std::string> doSomething();
另請參閱:C 中的 std::expected 是什么?
uj5u.com熱心網友回復:
std::variant是一個型別安全聯合,它允許您回傳一組固定型別中的一個。在這種情況下,您需要一個std::variant<std::string, int>
使用 std::variant
std::variant<std::string, int>doSomething(){
std::string value;
int rc = callApi(value);
if(rc == 0){ //if no error
//do some processing on value
return value;
}
return rc;
}
uj5u.com熱心網友回復:
std::optional不打算回傳錯誤。它是一個非常簡單的“有價值與否”概念的工具。來自 cppreference:
在任何給定時間點的任何 optional 實體要么包含值,要么不包含值。
如果您正在撰寫 C 函式并且錯誤不是您的業務邏輯的一部分(即,當您收到錯誤而不是可用結果時,您將不會繼續),只需拋出例外。std::runtime_error會很適合你。或者你可以使用std::error_code.
- 如果錯誤很少發生,拋出例外在性能方面是非常好的。
- 拋出例外可簡化您的程序邏輯。代替檢查每個結果的錯誤代碼,您可以捕獲一個例外。
uj5u.com熱心網友回復:
我將提出三個選項,但我相信有人會想出更聰明的方法。簡而言之:您可以拋出錯誤,您可以回傳自定義結構或類的實體,或者您可以使用 std::variant。
選項 1:拋出錯誤
在這里,您可以callApi在失敗時拋出錯誤值(即來自 的回傳碼),然后將任何呼叫包裝doSomething()在一個try ... catch塊中。
std::string doSomething(){
std::string value;
int rc = callApi(value);
if(rc) throw rc;
//do some processing on value
return value;
}
選項 2:回傳一個結構體
在這里,您創建一個包含 astd::string和回傳碼的結構體;這允許對錯誤資訊和成功回傳的字串進行編碼。
struct ReturnString {
std::string value;
int rc;
}
ReturnString doSomething(){
ReturnString return_value;
std::string & value = return_value.value;
int & rc = return_value.rc;
rc = callApi(value);
if(rc) return return_value;
//do some processing on value
return return_value;
}
然后,呼叫代碼可以檢查 的值rc,如果非零則適當處理錯誤,或者如果為 0 則使用字串。
您甚至可以花哨并使用通用結構,值的型別是模板引數。rc如果合適,您還可以添加幫助函式來檢查 的值以提供字串內容。但是,您可以使用標準庫中已經存在的類似內容,而不是做所有這些:
選項 3:使用變體
該std::variant代表一種型別安全的結合,因而可以承裝回傳代碼或字串。輔助函式可用于確定它持有哪一個。因此,您可能會執行以下操作:
std::variant<int, std::string> doSomething(){
std::variant<int, std::string> return_value;
std::string value;
int rc = callApi(value);
if(rc) return rc;
//do some processing on value
return return_value;
}
然后,從您的呼叫函式中,您可以檢查變體以查看它包含的型別,并相應地進行:
auto v = doSomething();
int rc;
if(std::holds_alternative<int>(v)) {
rc = std::get<int>(v);
//Process error accordingly
if(std::holds_alternative<std::string>(v)) {
std::cout << "String returned was " << std::get<std::string>(v) << std::endl;
}
uj5u.com熱心網友回復:
如果要回傳值或錯誤代碼,可以使用std::variant代替optional。例如
std::variant<std::string, int> doSomething() {
std::string value;
int err_code = callApi(value);
if (err_code == 0) {
//do some processing on value
return value;
}
return err_code;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/402503.html
標籤:
