콘텐츠로 이동

std::optional과 std::variant 활용

값이 있을 수도 없을 수도 있는 상황을 표현합니다. nullptr이나 sentinel 값(-1, 빈 문자열) 대신 사용합니다.

#include <optional>
std::optional<int> divide(int a, int b) {
if (b == 0) return std::nullopt;
return a / b;
}
auto result = divide(10, 2);
if (result) {
std::cout << *result; // 역참조
std::cout << result.value(); // 동일, 없으면 std::bad_optional_access
}
// 기본값 제공
int val = result.value_or(-1); // 없으면 -1
// 모나딕 연산 (C++23)
auto str = divide(10, 2)
.transform([](int v) { return std::to_string(v); })
.value_or("error");
std::optional<std::string> getConfig(std::string_view key);
std::optional<int> parsePort(std::string_view s);
auto port = getConfig("port")
.and_then(parsePort) // optional<int>로 변환
.transform([](int p){ return p + 1000; }) // 값 변환
.value_or(8080); // 기본값

여러 타입 중 하나를 타입 안전하게 저장합니다.

#include <variant>
using Value = std::variant<int, double, std::string>;
Value v = 42;
v = 3.14;
v = "hello";
// 타입 조회
if (std::holds_alternative<std::string>(v)) {
std::cout << std::get<std::string>(v);
}
// 인덱스로 접근
std::cout << std::get<0>(v); // int 꺼내기 (현재 std::string이면 예외)
// 안전한 접근
if (auto* p = std::get_if<int>(&v)) {
std::cout << *p;
}
Value v = 3.14;
std::visit([](auto&& val) {
using T = std::decay_t<decltype(val)>;
if constexpr (std::is_same_v<T, int>)
std::cout << "int: " << val;
else if constexpr (std::is_same_v<T, double>)
std::cout << "double: " << val;
else
std::cout << "string: " << val;
}, v);
template<typename... Ts>
struct overloaded : Ts... { using Ts::operator()...; };
Value v = "world";
std::visit(overloaded{
[](int i) { std::cout << "int: " << i; },
[](double d) { std::cout << "double: " << d; },
[](const std::string& s){ std::cout << "str: " << s; },
}, v);
using Result = std::variant<std::string, std::error_code>;
Result readFile(const std::string& path) {
std::ifstream f(path);
if (!f) return std::make_error_code(std::errc::no_such_file_or_directory);
return std::string{std::istreambuf_iterator<char>(f), {}};
}
auto res = readFile("data.txt");
std::visit(overloaded{
[](const std::string& s) { process(s); },
[](std::error_code ec) { std::cerr << ec.message(); },
}, res);
// variant의 첫 번째 타입을 monostate로 설정해 "초기화 안 됨" 상태 표현
std::variant<std::monostate, int, std::string> uninit;
// uninit.index() == 0 → monostate 상태
uninit = 42;
타입용도
optional<T>값이 있을 수도 없을 수도 있는 경우
variant<Ts...>여러 타입 중 하나 (타입 안전 union)
std::visitvariant에 대한 다형적 처리
monostatevariant의 초기화 안 된 상태
  • C++23 transform, and_then, or_else로 optional 체이닝 가능
  • overloaded 헬퍼로 visit 코드를 간결하게 작성