std::variant: 여러 형태 중 하나의 값 안전하게 표현하기
16강. std::variant: 여러 형태 중 하나의 값 안전하게 표현하기
이번 강의에서 해결할 문제
퀘스트 보상이 골드일 수도 아이템 이름일 수도 있을 때 void*, 공용체, 문자열 한 타입으로 억지로 표현하면 현재 값의 실제 타입을 별도 플래그와 맞춰 관리해야 합니다. 플래그와 값이 어긋나면 잘못된 메모리를 읽을 수 있습니다.
학습 목표
variant가 허용된 타입 중 하나를 보관함을 설명합니다.visit과if constexpr로 현재 타입을 처리합니다.- 타입 종류가 계속 늘어나는 설계에는 다른 모델이 필요할 수 있음을 판단합니다.
먼저 알아야 할 핵심 개념
std::variant<A, B>는 현재 A 또는 B 값 하나를 안전하게 보관하는 값 타입입니다. 타입 목록은 컴파일할 때 정해집니다. std::visit은 현재 활성 타입에 맞춰 호출 가능한 객체를 실행하므로 별도 타입 번호를 직접 맞출 필요가 없습니다.
가장 작은 실행 가능한 예제
#include <iostream>
#include <string>
#include <type_traits>
#include <variant>
using Reward = std::variant<int, std::string>;
void printReward(const Reward& reward) {
std::visit([](const auto& value) {
using Value = std::decay_t<decltype(value)>;
if constexpr (std::is_same_v<Value, int>) {
std::cout << "gold " << value << '\n';
} else {
std::cout << "item " << value << '\n';
}
}, reward);
}
int main() {
printReward(Reward{100});
printReward(Reward{std::string{"Sword"}});
}
핵심 코드 줄별 설명
Reward는 정수 골드 또는 문자열 아이템 이름만 허용합니다.visit은 현재 보관된 값과 맞는 람다 호출을 수행합니다.decltype(value)에서 참조·const를 제거해 실제 값 타입을 얻습니다.if constexpr는 선택되지 않은 타입 분기를 컴파일 대상에서 제외합니다.- 허용되지 않은
double보상을 넣으려 하면 변환 규칙에 따라 오류가 드러납니다.
실행 결과와 값 변화
gold 100
item Sword
두 번째 보상을 std::string{"Shield"}로 바꾸면 처리 구조는 그대로이고 출력 값만 달라집니다.
단계별 실습
실습 목표
퀘스트 결과를 경험치 또는 아이템으로 표현합니다.
시작 전 상태와 실행 방법
예제의 타입 별칭과 출력 함수를 C++17 프로젝트에 준비합니다.
1단계: 최소 코드 작성
경험치 정수와 아이템 문자열을 각각 만들어 visit으로 출력합니다.
2단계: 값 또는 조건을 바꿔 결과 비교
각 보상 값을 바꾸고 활성 타입이 유지되는지 확인합니다.
3단계: 작은 기능 확장
struct SkillReward { string name; }; 타입을 variant 목록에 추가하고 방문 분기를 작성합니다.
4단계: 스스로 해결하기
모든 타입에 공통 describe() 인터페이스를 두는 다형성 설계와 variant를 비교해 어느 쪽이 닫힌 타입 집합에 적합한지 설명하세요.
막혔을 때
새 타입을 추가한 뒤 방문 코드가 컴파일되지 않으면 그 타입에서 유효하지 않은 연산을 공통 분기에 사용했는지 확인합니다. if constexpr로 타입별 코드를 분리합니다.
흔한 실수와 해결 방법
- 타입 인덱스 숫자에 의존:
visit,holds_alternative,get_if처럼 타입 중심 API를 사용합니다. - 무한히 많은 타입을 한 variant에 추가: 확장 빈도가 높고 공통 동작이 중심이면 다형성이나 별도 데이터 모델을 검토합니다.
- 실패 상태까지 억지로 섞음: 값 없음은
optional, 오류 정보는 별도 결과 타입이 더 명확할 수 있습니다.
게임 개발 연결
고정된 보상 종류, 이벤트 페이로드, 설정 값처럼 허용 형태가 닫혀 있을 때 유용합니다. Unreal의 리플렉션·직렬화 시스템에 저장할 때는 표준 variant가 자동 노출되는지 가정하지 말고 엔진 지원 타입으로 경계를 변환합니다.
이해 점검 질문 3개
- variant가 타입 플래그와
void*조합보다 안전한 이유는 무엇인가요? visit은 현재 활성 값에 따라 무엇을 결정하나요?- 허용 타입이 자주 추가되는 시스템에서 variant가 불편해질 수 있는 이유는 무엇인가요?
핵심 요약
variant는 정해진 여러 타입 중 현재 하나의 값을 타입 안전하게 보관합니다. 닫힌 값 집합에는 효과적이지만 확장 방향과 처리 코드의 복잡도를 함께 판단합니다.
다음 강의 연결
17강. RAII 맛보기에서 값의 형태를 넘어 파일·잠금·메모리 같은 자원이 객체 수명에 따라 자동 정리되는 구조를 확인합니다.
std::variant: 여러 형태 중 하나의 값 안전하게 표현하기 미니 퀴즈
선택 즉시 정답과 해설을 확인할 수 있습니다. 결과는 이 브라우저에만 저장됩니다.
학습을 마쳤나요?
직접 실습과 점검 질문까지 확인한 뒤 완료로 표시하세요.