목차
1. typedef
2. 응용/심화
3. 요약
1. typedef
typedef : 타입에 별칭을 만드는 도구
// C++98
typedef int (*PFN_Compute)(int a, int b);
int Add(int a, int b) { return a + b; }
PFN_Compute fn = &Add;
-> fn(1,2)를 하게되면 Add(1,2)가 호출되며 3의 리턴값을 반환.
- typedef는 기존의 선언 문법을 그대로 따라가기 때문에 포인터 혹은 중첩 타입에서의 가독성이 급격하게 떨어짐.
-> 별칭(Alias)가 중간에 끼어들어 한 눈에 들어오지 않음.
2. 응용/심화
typedef vs using
typedef는 기존의 선언 문법을 그대로 따라가지만 using은 대입 연산자 형식을 사용.ex) ty[edef int (*PFN_HANDLER)(int, int); <-> using HandlerPtr = int(*)(int, int);-> 새로운 이름이 무엇인지 명확함.
// C++11+
using PFN_Compute = int (*)(int, int);
using Byte = unsigned char;
using Size = std::size_t;
- typedef는 템플릿 자체를 별칭으로 만들 수 없어 특정 타입으로 고정하거나 구조체 내부에 넣어 우회해야함.- using은 템플릿 인자를 그대로 유지하면서 별칭 생성 가능.
ex) 예시 : typedef
template <typename T>
struct SensorMap {
// 템플릿 별칭이 안 되어 구조체로 감싸야 함
typedef std::map<int, T> type;
};
SensorMap<float>::type myMap; // 사용 시 매번 ::type을 붙여야 함
ex) 예시 : using
template <typename T>
using SensorMap = std::map<int, T>; // 직관적인 템플릿 별칭
SensorMap<float> myMap; // 간결하고 명확함
ex) 선언 방식 비교
| 구분 | typedef 방식 (과거) | using 방식 (현대) |
| 기본 타입 | typedef int INT32; | using INT32 = int; |
| 배열 | typedef int ARR[10]; | using ARR = int[10]; |
| 함수 포인터 | typedef void (*PFN)(int); | using PFN = void (*)(int); |
타입 트레잇(Type Traits) 기반 설계와 typedef
컴파일 시간에 타입을 검사하고 변환하는 기법, 최근 C++ 설계 트렌드에서 선호.
-> typedef를 사용하는 경우 std::와 같은 메타 함수를 사용할 때, 매번 typename 키워드와 ::type을 붙여야하는 의존적 타입 문제에 직면.
ex) 예시 : typedef
template <typename T>
struct SensorMap {
// 템플릿 별칭이 안 되어 구조체로 감싸야 함
typedef std::map<int, T> type;
};
SensorMap<float>::type myMap; // 사용 시 매번 ::type을 붙여야 함
ex) 예시 : using
template <typename T>
using MyList = std::list<T>; // 별명 자체가 템플릿!
// 사용할 때 (매우 직관적)
MyList<int> m_list;
// 다른 템플릿 안에서 쓸 때도
template <typename T>
void Process() {
MyList<T> data; // 'typename' 필요 없음!
}
실무 가독성
현장에서는 Millisecond, ErrorCode와 같은 의미를 담은 타입을 정의하는 것이 중요.
-> 단순 int를 사용하는 것이 아닌 using TickCount = unsigned long;과 같은 의미를 부여.
// [의미 부여 전]
unsigned long start = GetTickCount();
int result = Connect();
// [의미 부여 후: using 활용]
using TickCount = unsigned long; // 시간 단위(ms)임을 명시
using ErrorCode = int; // 반환값이 단순 숫자가 아닌 에러코드임을 명시
TickCount startTime = GetTickCount();
ErrorCode connectionResult = Connect();
if (connectionResult == 0) { /* 성공 처리 */ }
CallBack 시크니처가 변경되는 경우 별칭 하나만 수정하면 프로젝트 전반에 안전하게 반영될 수 있도록.
// 1. 먼저 콜백의 형식을 별칭으로 정의합니다.
// (나중에 인자가 추가되어도 여기만 수정하면 됩니다.)
using OnReceiveCallback = void (*)(int deviceId, const char* data);
// 2. 실제 함수들
void MyDisplayLog(int id, const char* msg) { /* 로그 출력 */ }
// 3. 라이브러리 등록 함수
void RegisterCallback(OnReceiveCallback cb) { /* ... */ }
// [적용]
RegisterCallback(MyDisplayLog);
구 버전의 C++인 경우 typedef를 사용하되 주석을 통해 타입의 의도를 명확히 하고 가급적 함수 포인터 등은 단순화해서 정의.
/* * [구 버전 방식]
* 의미: 장치로부터 넘어오는 원시 데이터 처리 콜백
* PFN: Pointer to FuNction의 약어
*/
// 복잡한 함수 포인터를 한 번에 쓰지 말고 주석과 함께 정의
// void (*)(int, double) 형태
typedef void (*PFN_DeviceHandler)(int unitId, double value);
/* 시스템 전역에서 공유하는 핸들 타입 */
typedef unsigned int SYSTEM_HANDLE;
// 함수 정의 시 사용
void ProcessData(PFN_DeviceHandler handler, SYSTEM_HANDLE hSys) {
// 로직 구현
}
3. 요약
typedef : 타입에 별칭을 만드는 도구이지만 가독성이 떨어짐.
using : 타입 트레잇 기반 설계라는 최신 트렌드와 맞물려 typedef 대신 최신 C++에서 선호, 템플릿 별칭도 가능.
'Develop > Language - C++' 카테고리의 다른 글
| [C++] 정적 멤버선언 vs 동적 멤버 할당 (1) | 2026.01.23 |
|---|---|
| [ C++] 오버로딩 vs 오버라이딩 (0) | 2026.01.22 |
| [C++] extern과 using (0) | 2026.01.22 |
| [C++] 전방선언(Foward declaration) (0) | 2026.01.22 |
| [C++] #include < >vs #include " " (0) | 2026.01.22 |