반응형
Modern C++
에서는 하나의 함수(function
)에서 반환값(return value
)의 타입(type
)을 선택적으로 반환하는 다양한 방법이 있습니다.- 이 글에서는
C++11
부터C++23
까지 사용할 수 있는 여섯 가지 방법 을 소개하고, 각각의 장단점을 비교해 보겠습니다.
-
C++17에서 도입된
std::variant
는 하나의 변수에 여러 타입을 저장할 수 있는 방법입니다. -
cpp
#include <variant> #include <iostream> #include <string> std::variant<int, std::string> to_int(const std::string& text) { try { return std::stoi(text); } catch (...) { return "Invalid number: " + text; } } int main() { auto result = to_int("42"); if (std::holds_alternative<int>(result)) { std::cout << "Integer: " << std::get<int>(result) << "\n"; } else { std::cout << "Error: " << std::get<std::string>(result) << "\n"; } }
- ✅ 장점: 다양한 타입을 하나의 컨테이너로 묶을 수 있음.
- ❌ 단점:
std::get<>
또는std::visit
을 사용해야 함.
-
C++17
의std::optional
을 사용하면 값이 존재하는지 여부를 쉽게 표현 할 수 있습니다. -
cpp
#include <optional> #include <iostream> #include <string> std::optional<int> to_int(const std::string& text) { try { return std::stoi(text); } catch (...) { return std::nullopt; } } int main() { auto result = to_int("42"); if (result) { std::cout << "Integer: " << *result << "\n"; } else { std::cout << "Error: Invalid number\n"; } }
- ✅ 장점: 값이 존재하는지 여부만 판단하면 됨.
- ❌ 단점: 오류 메시지를 전달할 수 없음.
-
C++23
에서 도입된std::expected
는 성공값과 오류 메시지를 함께 표현 할 수 있는 공식적인 방법입니다. -
cpp
#include <expected> #include <iostream> #include <string> std::expected<int, std::string> to_int(const std::string& text) { try { return std::stoi(text); } catch (...) { return std::unexpected("Invalid number: " + text); } } int main() { auto result = to_int("42"); if (result) { std::cout << "Integer: " << *result << "\n"; } else { std::cout << "Error: " << result.error() << "\n"; } }
- ✅ 장점: 성공값과 실패값을 명확하게 구분 가능.
- ❌ 단점:
C++23
이상에서만 사용 가능.-
Compiler std::expected
지원 버전비고 GCC 13.1 이상 GCC Toolset 13부터 지원됩니다. Clang 16.0 이상 Clang 16부터 C++23 기능을 지원하기 시작했습니다. MSVC Visual Studio 2022 버전 17.6 (컴파일러 버전 19.36) 이상 C++23 기능이 포함되었습니다.
-
-
std::pair<int, std::string>
을 사용하면 첫 번째 요소에 변환된 값, 두 번째 요소에 오류 메시지를 저장 할 수 있습니다. -
cpp
#include <iostream> #include <string> #include <utility> std::pair<int, std::string> to_int(const std::string& text) { try { return { std::stoi(text), "" }; } catch (...) { return { 0, "Invalid number: " + text }; } } int main() { auto [value, error] = to_int("hello"); if (error.empty()) { std::cout << "Integer: " << value << "\n"; } else { std::cout << "Error: " << error << "\n"; } }
- ✅ 장점: 간단한 구조.
- ❌ 단점:
int
와std::string
이 동시에 존재하므로 다소 비효율적.
-
구조체를 사용하면 명확한 의미를 갖는 데이터를 반환 할 수 있습니다.
-
cpp
#include <iostream> #include <string> #include <optional> struct Result { std::optional<int> value; std::string error; }; Result to_int(const std::string& text) { try { return { std::stoi(text), "" }; } catch (...) { return { std::nullopt, "Invalid number: " + text }; } } int main() { auto result = to_int("42"); if (result.value) { std::cout << "Integer: " << *result.value << "\n"; } else { std::cout << "Error: " << result.error << "\n"; } }
- ✅ 장점: 가독성이 뛰어남.
- ❌ 단점: 구조체 정의가 필요함.
-
std::any
는 어떤 타입이든 반환할 수 있는 유연한 방법이지만, 런타임 타입 체크가 필요 합니다. -
cpp
#include <any> #include <iostream> #include <string> std::any to_int(const std::string& text) { try { return std::stoi(text); } catch (...) { return "Invalid number: " + text; } } int main() { auto result = to_int("42"); if (result.type() == typeid(int)) { std::cout << "Integer: " << std::any_cast<int>(result) << "\n"; } else { std::cout << "Error: " << std::any_cast<std::string>(result) << "\n"; } }
- ✅ 장점: 모든 타입을 지원
- ❌ 단점: 런타임 타입 체크 필요 (
typeid
와std::any_cast<>
사용)
방법 | C++ 버전 | 장점 | 단점 |
---|---|---|---|
std::variant<int, std::string> |
C++17 |
다양한 타입 반환 가능 | std::get<> 사용 필요 |
std::optional<int> |
C++17 |
단순한 성공/실패 표현 | 오류 메시지 전달 불가 |
std::expected<int, std::string> |
C++23 |
명확한 성공/실패 처리 | C++23 이상에서만 사용 가능 |
std::pair<int, std::string> |
C++11 |
쉬운 구현 | int 와 std::string 이 항상 존재 |
struct + std::optional |
C++11 |
명확한 의미 | 구조체 정의 필요 |
std::any |
C++17 |
모든 타입을 지원 | 런타임 타입 체크 필요 |
- ✅ 추천 방법
- C++17 이상:
std::variant<int, std::string>
- C++23 이상:
std::expected<int, std::string>
- 🚀 만약 오류 메시지가 필요 없다면? →
std::optional<int>
- 🔧 명확한 구조가 필요하다면? →
struct + std::optional
- C++17 이상:
728x90
반응형
'C C++' 카테고리의 다른 글
Modern C++ 의 std::visit 와 std::variant 가이드 (0) | 2025.03.04 |
---|---|
Modern C++ std::apply 사용법 및 예제 (0) | 2025.03.04 |
C/C++ CPU 캐시(cache) 활용 방안 (0) | 2025.03.04 |
c-vector : 표준 C++에서 볼 수 있는 것과 유사한 C의 동적 배열 (dynamic array) 구현 (0) | 2025.02.27 |
C++ 가상 테이블(vtable, virtual table)의 간접 참조(Indirection) (0) | 2025.02.19 |