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 타입의 인스턴스를 보유하는 객체 (클래스) |