std::variant
개념
std::variant
는 C++17 표준 라이브러리에서 도입된 타입으로, **여러 타입 중 하나의 값만 저장할 수 있는 타입 안전한 유니언(type-safe union)**이다.
std::variant
를 사용하면 여러 타입 중 하나의 값을 담되, 어떤 타입이 저장되었는지 컴파일 타임에 체크할 수 있다.
기본 사용법
#include <variant>
#include <iostream>
#include <string>
int main() {
std::variant<int, std::string> v;
v = 10;
std::cout << std::get<int>(v) << std::endl;
v = "hello";
std::cout << std::get<std::string>(v) << std::endl;
}
std::get<T>(variant)
를 사용하여 저장된 값을 원하는 타입으로 가져온다.
저장된 타입과 다른 타입으로 std::get
을 호출하면 std::bad_variant_access
예외가 발생한다.
생성자 예시
#include <variant>
#include <string>
#include <iostream>
int main() {
std::variant<int, std::string> v1(std::in_place_index<1>, 5, 'x');
std::variant<int, std::string> v2(std::in_place_type<std::string>, 5, 'x');
std::cout << std::get<1>(v1) << std::endl; // xxxxx
std::cout << std::get<std::string>(v2) << std::endl; // xxxxx
}
std::in_place_index<1>
는 인덱스 1(std::string
) 타입의 생성자를 직접 호출하여 초기화한다.
std::in_place_type<std::string>
는 타입으로 직접 지정하여 생성자를 호출한다.
값 접근 방식
값을 가져오는 방법에는 여러 가지가 있다.
std::variant<int, std::string> v = "hello";
// 방법 1: std::get
std::string s1 = std::get<std::string>(v);
// 방법 2: std::get_if
if (auto p = std::get_if<std::string>(&v)) {
std::cout << *p << std::endl;
}
std::get_if
는 포인터를 반환하며, 저장된 타입이 일치하지 않으면 nullptr을 반환한다.
방문자 패턴 (std::visit)
std::visit
를 사용하면 저장된 타입에 따라 다른 동작을 수행할 수 있다.
#include <variant>
#include <iostream>
#include <string>
int main() {
std::variant<int, std::string> v = "hello";
std::visit([](auto&& arg) {
std::cout << arg << std::endl;
}, v);
}
람다 함수는 저장된 값의 타입에 맞게 호출된다.
holds_alternative
특정 타입이 저장되었는지 확인할 때 std::holds_alternative
를 사용한다.
std::variant<int, std::string> v = 10;
if (std::holds_alternative<int>(v)) {
std::cout << "int 저장됨" << std::endl;
}
초기 값과 기본 인덱스
std::variant
는 첫 번째 타입(variant<int, std::string>
이면 int
)의 기본 생성자를 호출하여 초기화된다.
따라서 기본 생성 시 std::get<int>(v)
는 정의되어 있지만 std::get<std::string>(v)
는 사용할 수 없다.