01. 모듈의 목적과 전체 흐름
리플렉션은 프로그램이 자신의 타입, 멤버, 함수 등의 구조를 데이터로 조회 하고 활용할 수 있게 하는 기능입니다.
이 모듈은 C++ 선언의 정보를 실행 중 조회 하고, 지원되는 멤버에 접근할 수 있도록 만드는 도구입니다.
일반적인 코드는 특정 타입과 멤버를 알고 직접 접근합니다.
예를 들어:
struct Settings
{
float Speed = { 1.0f };
};
Settings settings;
settings.Speed = 2.f;
리플렉션을 사용하면 타입에 대한 설명 정보를 통해 여러 타입을 공통된 방식으로 처리할 수 있습니다.
다음 예제는 어노테이션 헤더와 사용자 정의 NAME 매크로가 준비돼 있고, 생성된 등록 코드를 통해 Settings 정보가 registry에 등록됐다고 가정한다.
STRUCT(NAME("Settings"))
struct Settings
{
PROPERTY(NAME("Speed"))
float Speed = { 1.0f };
};
Settings settings;
const auto* type = registry.FindType("Settings");
const auto* speed = type ? type->FindProperty("Speed") : nullptr;
if(speed != nullptr)
{
const bool written = speed->Write<float>(settings, 2.f);
}
이 예제는 이름을 이용한 멤버 조회를 보여준다. 여러 자료형을 공통으로 처리하려면 조회한 자료형 정보에 따른 처리도 필요하다.
매크로로 리플렉션 대상을 표시하면, 빌드 과정에서 해당 선언을 분석해 등록 코드를 생성합니다. 실행 시점에 이 코드를 통해 정보를 레지스트리에 등록하고, 문자열로 정보를 찾은 뒤 등록된 접근 기능을 사용합니다.
리플렉션에서 조회하는 타입, 멤버 정보와 실제 객체의 값은 서로 구분됩니다.
예를 들어 Settings::Speed 의 이름과 자료형은 타입에 대한 정보입니다.
반면 settings.Speed 에 저장된 2.0f 는 특정 객체가 가진 값입니다.
예를 들어:
Settings settingsA;
settingsA.Speed = 2.0f;
Settings settingsB;
settingsB.Speed = 5.0f;
두 객체는 같은 타입 정보를 사용하지만 각각 다른 값을 가집니다. 따라서 값을 읽거나 변경하려면 멤버 정보뿐 아니라 접근할 대상 객체도 필요합니다.
if(speed != nullptr)
{
speed->Write<float>(settingsA, 3.0f);
speed->Write<float>(settingsB, 6.0f);
}
이때 리플렉션 정보는 접근 방법을 제공하고, 실제 값은 대상 객체에 저장됩니다.
모듈의 목적
이 모듈의 목적은 타입마다 개별 처리 코드를 작성하는 부담을 줄이고, 타입과 멤버를 공통된 인터페이스로 조회하고 다룰 수 있도록 기반을 제공하는 것입니다.
이 정보를 활용하면 속성 편집, 직렬화, 스크립트 연동 등의 기능을 구성할 수 있습니다. 다만 리플렉션 모듈이 이러한 기능을 모두 직접 수행하는 것은 아닙니다. 정보를 어떻게 해석하고 활용할지는 사용하는 시스템이 결정합니다.
전체 처리 흐름
리플렉션은 일반적으로 다음 흐름으로 동작합니다.
타입·멤버 정보 확보
↓
조회 가능한 형태로 구성
↓
프로그램에서 정보 조회
↓
대상 객체에 대한 작업 수행
정보를 확보하는 방법은 구현에 따라 다릅니다. 개발자가 직접 등록할 수도 있고, 언어의 지원이나 코드 생성 도구를 사용할 수도 있습니다.
현재 모듈은 빌드 시점의 분석 및 코드 생성을 하고, 실행 시점에서 등록과 접근을 사용하는 방식을 선택했습니다.
빌드 시점
어노테이션 작성 → 선언 분석 → 등록 코드 생성 → 컴파일
실행 시점
정보 등록 → 타입·멤버 조회 → 객체의 값 접근 또는 함수 호출
헤더의 분석은 빌드 과정에서 수행합니다. 프로그램 실행 중에는 이미 생성하고 컴파일한 등록 코드와 접근 기능을 사용합니다.
Generator는 빌드 과정에서 선언을 분석하고 등록용 C++ 코드를 생성하는 도구다. 생성된 코드는 애플리케이션 코드와 함께 컴파일된다.
Runtime은 실행 중 타입 정보를 보관하고 조회하며, 등록된 접근 기능으로 대상 객체를 다루는 라이브러리다. 실행 중 헤더를 분석하지 않으므로 Runtime 사용에는 Clang·LLVM 분석 라이브러리가 필요하지 않다.
.gif)