utility_variant

utility_variant (타입 안전 공용체)

std::variant는 C++17에서 도입된 타입 안전 공용체(type-safe union) 클래스 템플릿이에요. variant 객체는 주어진 대안 타입 중 하나의 값을 저장하거나, 오류 상황에서는 값을 갖지 않는 상태가 돼요. 이 페이지에서는 std::variant의 정의, 멤버 함수, 비멤버 함수, 헬퍼 클래스 등을 설명할게요.

출처: cppreference

본문

정의

헤더에 정의됨
template < class ... Types > class variant ; (C++17부터)

클래스 템플릿 std::variant는 타입 안전 공용체를 나타내요.

variant 인스턴스는 주어진 시점에 대안 타입 중 하나의 값을 보유하거나, 오류가 발생한 경우 값이 없는 상태(이 상태는 달성하기 어려우며, valueless_by_exception 참고)가 돼요.

공용체와 마찬가지로, variant가 어떤 객체 타입 T의 값을 보유한다면 T 객체는 variant 객체 안에 중첩되어 있어요.

variant는 참조, 배열, void 타입을 보유할 수 없어요.

variant는 같은 타입을 여러 번 보유할 수 있고, cv 한정자가 다른 같은 타입의 버전도 보유할 수 있어요.

집합 초기화 중 공용체의 동작과 일관되게, 기본 생성된 variant는 첫 번째 대안의 값을 보유해요. 단, 그 대안이 기본 생성 가능하지 않으면 variant도 기본 생성 가능하지 않아요. 헬퍼 클래스 std::monostate를 사용하면 그러한 variant를 기본 생성 가능하게 만들 수 있어요.

템플릿 인자 없이 std::variant의 정의를 인스턴스화하는 프로그램은 ill-formed예요. 대신 std::variantstd::monostate를 사용할 수 있어요.

프로그램이 std::variant의 명시적 또는 부분 특수화를 선언하면, 진단이 필요 없이 ill-formed예요.

템플릿 매개변수

Types - 이 variant에 저장될 수 있는 타입들이에요. 모든 타입은 Destructible 요구 사항을 충족해야 해요 (특히 배열 타입과 비객체 타입은 허용되지 않아요).

멤버 함수

(생성자) variant 객체를 생성해요 (공개 멤버 함수)
(소멸자) variant와 포함된 값을 파괴해요 (공개 멤버 함수)
operator= variant를 할당해요 (공개 멤버 함수)
관찰자
index variant가 보유한 대안의 0부터 시작하는 인덱스를 반환해요 (공개 멤버 함수)
valueless_by_exception variant가 유효하지 않은 상태인지 확인해요 (공개 멤버 함수)
수정자
emplace variant 안에 값을 제자리에서 생성해요 (공개 멤버 함수)
swap 다른 variant와 교환해요 (공개 멤버 함수)
방문
visit (C++26) variant가 보유한 인자로 제공된 펑터를 호출해요 (공개 멤버 함수)

비멤버 함수

visit (C++17) 하나 이상의 variant가 보유한 인자들로 제공된 펑터를 호출해요 (함수 템플릿)
holds_alternative (C++17) variant가 현재 주어진 타입을 보유하는지 확인해요 (함수 템플릿)
get (std::variant) (C++17) 인덱스나 타입(타입이 유일한 경우)으로 variant의 값을 읽어요. 오류 시 예외를 던져요 (함수 템플릿)
get_if (C++17) 가리키는 variant의 값에 대한 포인터를 인덱스나 타입(유일한 경우)으로 얻어요. 오류 시 null을 반환해요 (함수 템플릿)
operator== operator!= operator< operator<= operator> operator>= operator<=> (C++17) (C++17) (C++17) (C++17) (C++17) (C++17) (C++20) variant 객체를 포함된 값으로 비교해요 (함수 템플릿)
std::swap (std::variant) (C++17) std::swap 알고리즘을 특수화해요 (함수 템플릿)

헬퍼 클래스

monostate (C++17) 기본 생성 불가능한 타입들의 variant에서 첫 번째 대안으로 사용하기 위한 자리표시자 타입 (클래스)
bad_variant_access (C++17) variant의 값에 대한 잘못된 접근 시 던져지는 예외 (클래스)
variant_size variant_size_v (C++17) 컴파일 타임에 variant의 대안 목록 크기를 얻어요 (클래스 템플릿) (변수 템플릿)
variant_alternative variant_alternative_t (C++17) 컴파일 타임에 인덱스로 지정된 대안의 타입을 얻어요 (클래스 템플릿) (별칭 템플릿)
std::hash std::variant (C++17) std::variant에 대한 해시 지원 (클래스 템플릿 특수화)

헬퍼 객체

variant_npos (C++17) 유효하지 않은 상태의 variant 인덱스 (상수)

참고 사항

기능 테스트 매크로 표준 기능
__cpp_lib_variant 201606L (C++17) std::variant: 타입 안전 공용체
202102L (C++23) (DR17) std::variant에서 파생된 클래스에 대한 std::visit
202106L (C++23) (DR20) 완전한 constexpr std::variant
202306L (C++26) 멤버 visit

예제

#include <cassert>
#include <iostream>
#include <string>
#include <variant>

int main()
{
    std::variant<int, float> v, w;
    v = 42; // v contains int
    int i = std::get<int>(v);
    assert(42 == i); // succeeds
    w = std::get<int>(v);
    w = std::get<0>(v); // same effect as the previous line
    w = v; // same effect as the previous line
    
//  std::get<double>(v); // error: no double in [int, float]
//  std::get<3>(v);      // error: valid index values are 0 and 1
    
    try
    {
        std::get<float>(w); // w contains int, not float: will throw
    }
    catch (const std::bad_variant_access& ex)
    {
        std::cout << ex.what() << '\n';
    }
    
    using namespace std::literals;
    
    std::variant<std::string> x("abc");
    // converting constructors work when unambiguous
    x = "def"; // converting assignment also works when unambiguous
    
    std::variant<std::string, void const*> y("abc");
    // casts to void const* when passed a char const*
    assert(std::holds_alternative<void const*>(y)); // succeeds
    y = "xyz"s;
    assert(std::holds_alternative<std::string>(y)); // succeeds
}

가능한 출력:

std::get: wrong index for variant

결함 보고서

다음 동작 변경 결함 보고서는 이전에 발표된 C++ 표준에 소급 적용되었어요.

DR 적용 대상 발표된 동작 올바른 동작
LWG 2901 C++17 std::uses_allocator 특수화가 제공되었지만 variant가 할당자를 제대로 지원할 수 없었음 특수화 제거
LWG 3990 C++17 프로그램이 std::variant의 명시적 또는 부분 특수화를 선언할 수 있었음 이 경우 프로그램은 ill-formed (진단 불필요)
LWG 4141 C++17 저장 공간 할당 요구 사항이 혼란스러웠음 포함된 객체는 variant 객체 안에 중첩되어야 함

같이 보기

in_place in_place_type in_place_index in_place_t in_place_type_t in_place_index_t (C++17) 제자리 생성 태그 (태그)
optional (C++17) 객체를 보유할 수도 있고 보유하지 않을 수도 있는 래퍼 (클래스 템플릿)
any (C++17) 임의의 CopyConstructible 타입의 인스턴스를 보유하는 객체 (클래스)

더 알아보기

cppreference