요새 C++에서 사용하고 있는 std::variant라는 걸로 개발을 해보고 있다. 생소해서 사용방법을 잠깐 남겨본다. 약간 C에서 Union같은 느낌도 나지만 그 느낌은 객체스럽다.
C++의 std::variant는 여러 타입 중 하나의 값을 가질 수 있는 타입-안전한 유니언(union)이다.
std::variant는 C++17부터 표준 라이브러리에 포함되었다고 하니 17이상으로 써야한다.
1. std::variant 기본 사용법
#include <iostream>
#include <variant>
int main() {
std::variant<int, double, std::string> v; // int, double, std::string 중 하나 저장 가능
v = 42; // int 저장
std::cout << "int: " << std::get<int>(v) << '\n';
v = 3.14; // double 저장
std::cout << "double: " << std::get<double>(v) << '\n';
v = "Hello, Variant!"; // std::string 저장
std::cout << "string: " << std::get<std::string>(v) << '\n';
return 0;
}
- std::variant<int, double, std::string>은 int, double, std::string 중 하나를 저장할 수 있습니다.
- std::get<T>(variant)로 현재 저장된 값을 가져올 수 있습니다.
2. 현재 저장된 타입 확인 (index()와 std::holds_alternative<T>)
요것이 특이하다. 저장된 타입을 알 수 있게 해준다. Union같았으면.. 개발자가 알아서..했던 일?
#include <iostream>
#include <variant>
int main() {
std::variant<int, double, std::string> v = 3.14;
std::cout << "Current index: " << v.index() << '\n'; // 현재 저장된 타입의 인덱스 출력
if (std::holds_alternative<double>(v)) { // double 타입인지 확인
std::cout << "v contains a double: " << std::get<double>(v) << '\n';
}
return 0;
}
- v.index()는 현재 저장된 타입의 인덱스를 반환합니다.
- std::holds_alternative<T>(v)를 사용하면 현재 저장된 값의 타입이 T인지 확인할 수 있습니다.
3. std::get_if<T>()를 사용하여 안전하게 값 접근
#include <iostream>
#include <variant>
int main() {
std::variant<int, double, std::string> v = "C++ Variant";
if (auto ptr = std::get_if<std::string>(&v)) { // std::string 타입이면 포인터 반환
std::cout << "Stored string: " << *ptr << '\n';
} else {
std::cout << "Not a string!\n";
}
return 0;
}
- std::get_if<T>(&v)는 현재 타입이 T일 때 포인터를 반환하고, 그렇지 않으면 nullptr을 반환합니다.
- 이를 통해 예외 없이 안전하게 값을 확인할 수 있습니다.
4. std::visit을 사용한 방문자 패턴
#include <iostream>
#include <variant>
void printVariant(const std::variant<int, double, std::string>& v) {
std::visit([](auto&& arg) {
std::cout << "Value: " << arg << '\n';
}, v);
}
int main() {
std::variant<int, double, std::string> v = 42;
printVariant(v);
v = 3.14;
printVariant(v);
v = "Hello, World!";
printVariant(v);
return 0;
}
- std::visit은 std::variant의 현재 저장된 타입에 따라 적절한 람다 함수를 실행합니다.
- auto&&를 사용하면 모든 타입을 처리할 수 있습니다.
5. 예외 처리 (std::bad_variant_access)
잘못된 타입으로 std::get<T>(v)를 호출하면 std::bad_variant_access 예외가 발생합니다.
#include <iostream>
#include <variant>
int main() {
std::variant<int, double> v = 3.14;
try {
std::cout << std::get<int>(v) << '\n'; // 현재 저장된 타입이 int가 아니므로 예외 발생
} catch (const std::bad_variant_access& e) {
std::cout << "Exception: " << e.what() << '\n';
}
return 0;
}
- std::bad_variant_access 예외를 처리하여 프로그램이 크래시되지 않도록 할 수 있습니다.
댓글