type_traits

MwG·2026년 3월 26일

C++

목록 보기
21/21

type_traits

타입들에 대해 여러가지 연산을 수행할 수 있는 메타 함수들을 제공하고 있다.

static_assert

static_assert(bool 타입의 constexpr)
전달된 식이 참이라면 컴파일러에 의해 해당 식은 무시되고 거짓이라면 해당 문장에서 컴파일 오류 발생시킴

integral_constant<T, T v>

v를 static 인자로 가지는 클래스 -> 어떠한 값을 static 객체로 가지고 있는 클래스를 만들어주는 템플릿

데이터 멤버를 가리키는 포인터(Pointer to Data member)

클래스와 공용체에서만 사용가능

int T::* //T의 int멤버를 가리키는 포인터
class A
{
public:
	int n;

	A(int n) :n(n){}


};


int main()
{
	int A::* p_n = &A::n;

	A a(3);


	std::cout << a.n << "\n";
	std::cout << a.*p_n;

	return 0;
}

SFINAE(치환오류는 컴파일 오류가 아니다)

컴파일 오류 발생 대신 함수의 오버로딩 후보군에서만 제외된다.

enable_if

template<bool B, class T = void>
struct enable_if;

B가 참일때 enable_if::value의 타입이 T가 되고
B가 거짓일때 value가 존재하지 않게 된다.

1. 기반 다지기(ai 사용)

type_traits와 integral_constant

C++에서 타입에 대한 정보를 컴파일 타임에 알아내고 조작하려면, '값(value)'을 '타입(type)'으로 승격시키는 작업이 필요합니다.

std::integral_constant<T, v>: 변수 v(값)를 템플릿 인자로 받아 하나의 독립된 타입으로 만들어주는 래퍼(Wrapper)입니다.

왜 필요한가?

템플릿 메타프로그래밍에서는 런타임의 if (bool) 대신, 컴파일 타임의 타입 매칭을 통해 분기를 태워야 합니다. 그래서 integral_constant<bool, true>를 std::true_type으로, false를 std::false_type으로 미리 정의해 둡니다.

연결

<type_traits> 헤더에 있는 수많은 메타 함수들(예: is_pointer, is_arithmetic)은 조건을 만족하면 true_type을, 아니면 false_type을 상속받도록 구현되어 있습니다.

2. 안전망 구축: static_assert

템플릿은 아무 타입이나 다 받아주기 때문에 잘못된 타입이 들어오면 에러 메시지가 걷잡을 수 없이 길어집니다.

역할

컴파일 타임의 assert입니다. 주로 type_traits와 결합하여 입력된 타입이 내가 원하는 조건이 맞는지 입구 컷을 담당합니다.

활용

예를 들어, 네트워크 패킷이나 게임 세이브 데이터를 고속으로 복사(memcpy)하는 템플릿 함수를 만들 때, static_assert(std::is_trivially_copyable_v, "안전하게 복사할 수 없는 타입입니다!");라고 선언하여 치명적인 런타임 메모리 버그를 컴파일 타임에 차단합니다.

3. 구조적 유연성

데이터 멤버를 가리키는 포인터 (Type::*)

일반 포인터가 메모리의 특정 '절대 주소'를 가리킨다면, 멤버 포인터는 클래스 시작점으로부터의 '상대적 위치(Offset)'를 가리킵니다.

핵심

객체가 아직 생성되지 않았어도(인스턴스가 없어도), 클래스 내부에 어떤 변수들이 있는지를 가리킬 수 있습니다. 사용할 때는 반드시 실제 인스턴스(a.p_n)나 포인터(pa->p_n)가 필요합니다.

활용

엔진의 리플렉션(Reflection) 시스템이나 인스펙터(UI) 창을 구현할 때 핵심이 됩니다. "Player 클래스의 hp 변수 위치"를 멤버 포인터로 맵핑해두면, 나중에 어떤 Player 인스턴스가 들어오든 범용적인 코드로 hp 값을 읽고 쓸 수 있습니다.

4. 컴파일 타임 분기의 꽃: SFINAE와 enable_if

이 모든 것을 조합하여 컴파일러가 알아서 알맞은 함수를 선택하게 만드는 마법입니다.

SFINAE (치환 실패는 에러가 아니다)

컴파일러가 템플릿 타입(T)을 추론하여 끼워 넣다가 문법적으로 말이 안 되는 상황이 발생하면, 에러를 내뿜고 죽는 대신 "어? 이 함수는 아니네? 다른 오버로딩 함수 찾아볼까?" 하고 쿨하게 넘어가는 규칙입니다.

std::enable_if<B, T>:

SFINAE 규칙을 우리가 원하는 대로 조종하기 위한 스위치입니다.

조건 B(주로 type_traits의 결과)가 참(true)이면: 내부에 type이라는 멤버(T)가 생성됩니다. (치환 성공 -> 함수 후보 등록)

조건 B가 거짓(false)이면: 내부에 type이 아예 정의되지 않습니다. 컴파일러가 ::type을 찾으려다 실패하므로 SFINAE가 발동합니다. (치환 실패 -> 함수 후보에서 조용히 탈락)

0개의 댓글