As I am beginning to take advantage of the C++17 structured bindings and if operator init statements for more elegant function result reporting and checking, I started doing the following, if accordance with C++ Core Guideline F21:
std::pair<bool, int>Foo()
{
return {true, 42}; //true means that function complete with no error and that 42 is a good value
}
void main(void)
{
if (auto [Result, Value] = Foo(); Result)
{
//Do something with the return value here
}
}
Then, of course, I though that it would be nice to have a reusable template for such return types so that nobody has to duplicate bool portion of the pair:
template <typename T> using validated = std::pair<bool,T>;
validated<int> Foo()
{
return {true, 42};
}
void main(void)
{
if (auto [Result, Value] = Foo(); Result)
{
//Do something with the return value here
}
}
This works great for me, but now I am wondering if there is some sort of standard equivalent of this template so that I don't have to reinvent the wheel and define it myself. Seems like an arbitrary type value coupled with a validity flag would be a useful construct, but I could not find anything in standard library. Am I missing something?
std::optional is exactly what you are asking about. It's even in the description:
A common use case for optional is the return value of a function that may fail. As opposed to other approaches, such as
std::pair<T,bool>
, optional handles expensive-to-construct objects well and is more readable, as the intent is expressed explicitly.
The if
from the example would look a bit more straightforward:
#include <optional>
#include <iostream>
std::optional<int> Foo(bool fail)
{
if (!fail) return {42};
return {};
}
void process(bool fail) {
if (auto val = Foo(fail)) {
std::cout << val.value() << '\n';
} else {
std::cout << "No value!\n";
}
}
int main() {
std::optional<int> oi;
process(true);
process(false);
}
If you really wished to use Value
explicitly then you can always unpack it via reference on a successful branch i.e. auto Value = val.value()
;
You need to beware of some caveats. 2 from the top of my head:
Note:
static
was added forprocess
for brevity - to prevent generation of version for external linking.
false
if object was default constructed. That might surprise some, default construction of optional
doesn't default construct underlying value.EDIT:
After the comments I decided to explicitly state that there isn't anything like type alias for pair<T,bool>
or similar compatible with standard library. It's not easy to prove something does not exist, but if there would such a type the standard library would most certainly used it in declaration of insert
, it doesn't; hence, I strongly imply that there isn't any semantic wrapper around it.
You might be interested in the proposed std::expected
.
Its interface follows std::optional
pretty closely. The major advantage of
expected<T, E>
over optional<T>
is the ability to transport an error:
enum class errc {err1, err2, err3};
std::expected<int, errc> Foo()
{
if (/* error condition 1 */) return std::unexpected(errc::err1);
// ... checking other error conditions
return 42; // no error condition (42 is a good value)
// implicit conversion from `int` to `expected<int, errc>`
// avoid boilerplate code
}
int main()
{
auto q = Foo();
if (q)
{
// Do something with the return value here
}
}
You could also take a look at:
As a side note main()
must return int
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With