Vocabulary Types & Utilities
C++17 introduced several vocabulary types and utilities that make code safer and more expressive, reducing the need for custom error handling or complex type hierarchies.
std::optional (Maybe a Value)
std::optional<T> represents a value that may or may not be present. It is a safer alternative to returning pointers (which can be null) or magic values (like -1).
| #include <optional>
std::optional<int> parse_int(const std::string& str) {
if (is_valid_number(str)) {
return std::stoi(str);
}
return std::nullopt; // No value
}
auto result = parse_int("123");
if (result) { // Check if value exists
std::cout << "Value: " << *result; // Access value
} else {
std::cout << "Invalid number";
}
// Use default value if empty
int value = result.value_or(0);
|
std::variant (Type-Safe Union)
std::variant<T, U, ...> can hold a value of one of the specified types. It is a type-safe replacement for C-style union.
| #include <variant>
std::variant<int, float, std::string> data;
data = 10;
data = 3.14f;
data = "Hello";
// Accessing values
if (std::holds_alternative<std::string>(data)) {
std::cout << std::get<std::string>(data);
}
// Visiting (Pattern Matching)
std::visit([](auto&& arg) {
std::cout << arg;
}, data);
|
std::any (Type Erasure)
std::any can hold a value of any copyable type. It is more flexible than variant but less efficient and requires any_cast to retrieve the value.
| #include <any>
std::any a = 1;
a = std::string("Hello");
try {
std::string s = std::any_cast<std::string>(a);
} catch (const std::bad_any_cast& e) {
std::cout << e.what();
}
|
std::expected (C++23)
std::expected<T, E> represents either a value of type T (success) or an error of type E (failure). It is cleaner than exceptions for expected errors.
| #include <expected>
#include <iostream>
enum class Error { DivideByZero };
std::expected<int, Error> divide(int a, int b) {
if (b == 0) return std::unexpected(Error::DivideByZero);
return a / b;
}
auto result = divide(10, 0);
if (result) {
std::cout << "Result: " << *result;
} else {
std::cout << "Error occurred";
}
|
Filesystem Library (std::filesystem)
The <filesystem> library provides a portable way to interact with the file system.
| #include <filesystem>
namespace fs = std::filesystem;
void list_files(const fs::path& dir_path) {
if (fs::exists(dir_path) && fs::is_directory(dir_path)) {
for (const auto& entry : fs::directory_iterator(dir_path)) {
std::cout << entry.path().filename() << "\n";
}
}
}
// Creating directories
fs::create_directory("logs");
// Copying files
fs::copy_file("config.txt", "config.bak", fs::copy_options::overwrite_existing);
|