본문으로 건너뛰기
모던 C++LESSON 16

std::variant: 여러 형태 중 하나의 값 안전하게 표현하기

난이도초급 → 중급 입문
예상 시간45분
선수지식이전 강의

16강. std::variant: 여러 형태 중 하나의 값 안전하게 표현하기

이번 강의에서 해결할 문제​

퀘스트 보상이 골드일 수도 아이템 이름일 수도 있을 때 void*, 공용체, 문자열 한 타입으로 억지로 표현하면 현재 값의 실제 타입을 별도 플래그와 맞춰 관리해야 합니다. 플래그와 값이 어긋나면 잘못된 메모리를 읽을 수 있습니다.

학습 목표​

  • variant가 허용된 타입 중 하나를 보관함을 설명합니다.
  • visit과 if constexpr로 현재 타입을 처리합니다.
  • 타입 종류가 계속 늘어나는 설계에는 다른 모델이 필요할 수 있음을 판단합니다.

먼저 알아야 할 핵심 개념​

std::variant<A, B>는 현재 A 또는 B 값 하나를 안전하게 보관하는 값 타입입니다. 타입 목록은 컴파일할 때 정해집니다. std::visit은 현재 활성 타입에 맞춰 호출 가능한 객체를 실행하므로 별도 타입 번호를 직접 맞출 필요가 없습니다.

가장 작은 실행 가능한 예제​

variant_reward.cpp
#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"}});
}

핵심 코드 줄별 설명​

  1. Reward는 정수 골드 또는 문자열 아이템 이름만 허용합니다.
  2. visit은 현재 보관된 값과 맞는 람다 호출을 수행합니다.
  3. decltype(value)에서 참조·const를 제거해 실제 값 타입을 얻습니다.
  4. if constexpr는 선택되지 않은 타입 분기를 컴파일 대상에서 제외합니다.
  5. 허용되지 않은 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개​

  1. variant가 타입 플래그와 void* 조합보다 안전한 이유는 무엇인가요?
  2. visit은 현재 활성 값에 따라 무엇을 결정하나요?
  3. 허용 타입이 자주 추가되는 시스템에서 variant가 불편해질 수 있는 이유는 무엇인가요?

핵심 요약​

variant는 정해진 여러 타입 중 현재 하나의 값을 타입 안전하게 보관합니다. 닫힌 값 집합에는 효과적이지만 확장 방향과 처리 코드의 복잡도를 함께 판단합니다.

다음 강의 연결​

17강. RAII 맛보기에서 값의 형태를 넘어 파일·잠금·메모리 같은 자원이 객체 수명에 따라 자동 정리되는 구조를 확인합니다.

MINI QUIZ

std::variant: 여러 형태 중 하나의 값 안전하게 표현하기 미니 퀴즈

선택 즉시 정답과 해설을 확인할 수 있습니다. 결과는 이 브라우저에만 저장됩니다.

0 / 2
  1. 문제 1“std::variant: 여러 형태 중 하나의 값 안전하게 표현하기” 작업 전 검토에서 채택해야 할 안전 기준은 무엇인가요?
  2. 문제 2“std::variant: 여러 형태 중 하나의 값 안전하게 표현하기”의 작업 기준으로 ‘실패 상태까지 억지로 섞음’을 진단하거나 바로잡은 선택은 무엇인가요?
LESSON STATUS

학습을 마쳤나요?

직접 실습과 점검 질문까지 확인한 뒤 완료로 표시하세요.

16강. std::variant: 여러 형태 중 하나의 값 안전하게 표현하기 미완료 상태