본문 바로가기
개발/C++

[C++] std::variant 쓰는 법

by lucidmaj7 2025. 3. 16.

요새 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 예외를 처리하여 프로그램이 크래시되지 않도록 할 수 있습니다.

 

댓글