개념

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)는 사용할 수 없다.

참고 문서

https://en.cppreference.com/w/cpp/utility/variant