std::optional과 std::variant 활용
std::optional
섹션 제목: “std::optional”값이 있을 수도 없을 수도 있는 상황을 표현합니다. 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");optional 체이닝 (C++23)
섹션 제목: “optional 체이닝 (C++23)”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); // 기본값std::variant
섹션 제목: “std::variant”여러 타입 중 하나를 타입 안전하게 저장합니다.
#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;}std::visit로 패턴 매칭
섹션 제목: “std::visit로 패턴 매칭”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);overloaded 헬퍼
섹션 제목: “overloaded 헬퍼”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);std::monostate — 빈 상태 표현
섹션 제목: “std::monostate — 빈 상태 표현”// variant의 첫 번째 타입을 monostate로 설정해 "초기화 안 됨" 상태 표현std::variant<std::monostate, int, std::string> uninit;// uninit.index() == 0 → monostate 상태uninit = 42;| 타입 | 용도 |
|---|---|
optional<T> | 값이 있을 수도 없을 수도 있는 경우 |
variant<Ts...> | 여러 타입 중 하나 (타입 안전 union) |
std::visit | variant에 대한 다형적 처리 |
monostate | variant의 초기화 안 된 상태 |
- C++23
transform,and_then,or_else로 optional 체이닝 가능 overloaded헬퍼로 visit 코드를 간결하게 작성