C++23 std::expected 오류 처리
std::expected<T, E>는 C++23에서 도입된 값 또는 오류를 담는 타입입니다. 함수가 성공하면 T 값을, 실패하면 E 오류를 반환합니다. 예외를 던지지 않으면서도 오류 정보를 명시적으로 전달할 수 있습니다.
1. 기본 사용
섹션 제목: “1. 기본 사용”#include <expected>#include <string>#include <charconv>
enum class ParseError { InvalidInput, Overflow };
std::expected<int, ParseError> parse_int(std::string_view s){ int result{}; auto [ptr, ec] = std::from_chars(s.begin(), s.end(), result);
if (ec == std::errc::invalid_argument) return std::unexpected(ParseError::InvalidInput); if (ec == std::errc::result_out_of_range) return std::unexpected(ParseError::Overflow);
return result; // 성공}
int main(){ if (auto val = parse_int("42")) std::cout << *val << '\n'; // 42 else std::cout << "오류\n";
auto bad = parse_int("abc"); if (!bad) // bad.error() == ParseError::InvalidInput std::cout << "파싱 실패\n";}2. 모나딕 체이닝 연산자
섹션 제목: “2. 모나딕 체이닝 연산자”C++23은 and_then, or_else, transform, transform_error 네 가지 체이닝 연산자를 제공합니다.
#include <expected>#include <string>
std::expected<std::string, std::string> read_file(const std::string& path);std::expected<int, std::string> parse_config(const std::string& content);std::expected<void, std::string> apply_config(int value);
void load_settings(const std::string& path){ auto result = read_file(path) .and_then(parse_config) // 성공 시 다음 단계 .and_then(apply_config) // 성공 시 다음 단계 .transform_error([](auto& err) { // 오류 타입 변환 return "설정 로드 실패: " + err; });
if (!result) std::cerr << result.error() << '\n';}3. transform — 성공 값 변환
섹션 제목: “3. transform — 성공 값 변환”auto doubled = parse_int("21") .transform([](int v) { return v * 2; }); // expected<int, ParseError>{42}
auto as_string = parse_int("42") .transform([](int v) { return std::to_string(v); }); // expected<string, ParseError>4. or_else — 오류 복구
섹션 제목: “4. or_else — 오류 복구”auto recovered = parse_int("bad") .or_else([](ParseError) { return std::expected<int, ParseError>{0}; // 기본값 반환 });// *recovered == 05. std::optional vs std::expected
섹션 제목: “5. std::optional vs std::expected”| 항목 | std::optional<T> | std::expected<T, E> |
|---|---|---|
| 오류 정보 | 없음 (nullopt) | 있음 (E 타입) |
| 오류 종류 구분 | 불가 | 가능 |
| 체이닝 | transform, and_then | 동일 + or_else |
| 용도 | ”값이 없을 수 있는” 상황 | ”실패 이유가 있는” 상황 |
6. 실전 패턴 — 파일 파싱 파이프라인
섹션 제목: “6. 실전 패턴 — 파일 파싱 파이프라인”#include <expected>#include <fstream>#include <string>
enum class FileError { NotFound, PermissionDenied, ParseFailed };
std::expected<std::string, FileError> read_file(const std::string& path){ std::ifstream f(path); if (!f) return std::unexpected(FileError::NotFound); return std::string(std::istreambuf_iterator<char>(f), {});}
std::expected<Config, FileError> load_config(const std::string& path){ return read_file(path) .and_then([](const std::string& content) -> std::expected<Config, FileError> { if (content.empty()) return std::unexpected(FileError::ParseFailed); return Config::parse(content); });}7. value_or — 기본값 제공
섹션 제목: “7. value_or — 기본값 제공”int val = parse_int("bad").value_or(0); // 오류 시 0 반환std::expected는 예외 비용 없이 함수 실패 이유를 타입 시스템으로 표현합니다. and_then 체이닝으로 여러 단계를 깔끔하게 연결하고, 오류가 발생한 지점부터 자동으로 이후 단계를 건너뜁니다. 오류 이유가 중요한 시스템 경계 함수에서 std::optional 대신 사용하세요.