I'll present three options, though I'm sure somebody will come up with a more clever approach. In short: you could throw an error, you could return an instance of a custom struct or class, or you could use a std::variant.
Option 1: Throw an Error
Here, you can throw the error value (i.e. the return code from callApi
) on failure, then wrap any calls to doSomething()
in a try ... catch
block.
std::string doSomething(){
std::string value;
int rc = callApi(value);
if(rc) throw rc;
//do some processing on value
return value;
}
Option 2: Return a Struct
Here, you create a struct that holds both a std::string
and a return code; this allows the encoding of both error information and a successfully-returned 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;
}
Then, calling code can check the value of rc
, process the error appropriately if nonzero, or use the string if 0.
You could even get fancy and use a generic struct, with the type of value being a template parameter. You could additionally add helper functions that check the value of rc
to give you the string contents if appropriate. Rather than doing all that, though, you can use something similar that already exists in the standard library:
Option 3: Use a Variant
The std::variant
represents a type-safe union, and thus can hold either a return code or a string. Helper functions can be used to determine which one it holds. So, you might do something like:
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;
}
Then, from your calling function, you can check the variant to see which type it holds, and proceed accordingly:
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;
}