[2026] C++ using vs typedef | 타입 별칭 빠른 비교

[2026] C++ using vs typedef | 타입 별칭 빠른 비교

이 글의 핵심

typedef와 using의 차이를 표와 짧은 예제로 빠르게 비교합니다. 함수 포인터·템플릿 별칭·실무 팁은 심화 글 cpp-typedef-using에서 이어집니다.

이 글과 형제 글의 역할

  • 이 글 (cpp-using-typedef): 빠른 비교—표, 짧은 코드, 언제 무엇을 쓰는지 요약.
  • 심화 글 (C++ typedef vs using | 타입 별칭 심화 가이드): 함수·멤버 함수 포인터, 템플릿 별칭, 가독성·실무 패턴을 더 길게 다룹니다. 같은 주제를 두 번 읽는 대신, 필요에 따라 위 둘 중 하나만 골라도 됩니다.

타입 별칭이란?

타입 별칭 (Type Alias)기존 타입에 새 이름을 부여하는 기능입니다. C++03의 typedef와 C++11의 using이 있습니다. 아래 코드는 cpp를 사용한 구현 예제입니다. 필요한 모듈을 import하고. 코드를 직접 실행해보면서 동작을 확인해보세요.

// typedef (C++03)
typedef unsigned long ulong;
typedef std::vector<int> IntVec;
// using (C++11)
using ulong = unsigned long;
using IntVec = std::vector<int>;

왜 필요한가?:

  • 가독성: 복잡한 타입을 간결하게
  • 유지보수: 타입 변경 시 한 곳만 수정
  • 추상화: 구현 세부사항 숨김
  • 이식성: 플랫폼별 타입 통일 아래 코드는 cpp를 사용한 구현 예제입니다. 필요한 모듈을 import하고. 코드를 직접 실행해보면서 동작을 확인해보세요.
// ❌ 복잡한 타입: 읽기 어려움
std::map<std::string, std::vector<std::pair<int, double>>> data;
// ✅ 타입 별칭: 간결
using DataMap = std::map<std::string, std::vector<std::pair<int, double>>>;
DataMap data;

typedef vs using 비교:

특징typedefusing
문법C 스타일현대적
가독성낮음높음
템플릿 별칭❌ 불가✅ 가능
함수 포인터복잡간결
권장❌ 레거시✅ C++11+
아래 코드는 cpp를 사용한 구현 예제입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
// typedef: 복잡
typedef void (*FuncPtr)(int, double);
// using: 간결
using FuncPtr = void(*)(int, double);
// typedef: 템플릿 별칭 불가
template<typename T>
typedef std::vector<T> Vec;  // 에러!
// using: 템플릿 별칭 가능
template<typename T>
using Vec = std::vector<T>;

typedef 기본

다음은 cpp를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// 기본 타입
typedef int Integer;
typedef double Real;
Integer x = 10;
Real y = 3.14;
// 포인터
typedef int* IntPtr;
IntPtr ptr = &x;
// 배열
typedef int IntArray[10];
IntArray arr = {1, 2, 3};
// 함수 포인터
typedef int (*FuncPtr)(int, int);
FuncPtr func = add;

using 기본

아래 코드는 cpp를 사용한 구현 예제입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// 기본 타입
using Integer = int;
using Real = double;
// 포인터
using IntPtr = int*;
// 배열
using IntArray = int[10];
// 함수 포인터
using FuncPtr = int(*)(int, int);

using vs typedef

아래 코드는 cpp를 사용한 구현 예제입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// typedef: 읽기 어려움
typedef void (*FuncPtr)(int, double);
// using: 읽기 쉬움
using FuncPtr = void(*)(int, double);
// typedef: 템플릿 별칭 불가
template<typename T>
typedef std::vector<T> Vec;  // 에러!
// using: 템플릿 별칭 가능
template<typename T>
using Vec = std::vector<T>;

실전 예시

예시 1: 컨테이너 별칭

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <vector>
#include <map>
#include <string>
// 자주 사용하는 타입
using StringVec = std::vector<std::string>;
using IntMap = std::map<std::string, int>;
using Matrix = std::vector<std::vector<int>>;
int main() {
    StringVec names = {"Alice", "Bob", "Charlie"};
    
    IntMap ages = {
        {"Alice", 30},
        {"Bob", 25}
    };
    
    Matrix grid = {
        {1, 2, 3},
        {4, 5, 6},
        {7, 8, 9}
    };
}

예시 2: 함수 포인터

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// typedef 방식
typedef int (*Operation)(int, int);
// using 방식 (더 명확)
using Operation = int(*)(int, int);
int add(int a, int b) { return a + b; }
int multiply(int a, int b) { return a * b; }
int calculate(int a, int b, Operation op) {
    return op(a, b);
}
int main() {
    cout << calculate(10, 5, add) << endl;       // 15
    cout << calculate(10, 5, multiply) << endl;  // 50
}

예시 3: 템플릿 별칭

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// 스마트 포인터 별칭
template<typename T>
using UniquePtr = std::unique_ptr<T>;
template<typename T>
using SharedPtr = std::shared_ptr<T>;
// 컨테이너 별칭
template<typename T>
using Vec = std::vector<T>;
template<typename K, typename V>
using Map = std::map<K, V>;
int main() {
    UniquePtr<int> ptr = std::make_unique<int>(42);
    Vec<int> numbers = {1, 2, 3, 4, 5};
    Map<std::string, int> ages = {{"Alice", 30}};
}

예시 4: 복잡한 타입 간소화

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 클래스를 정의하여 데이터와 기능을 캡슐화하며, 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <functional>
#include <vector>
// 복잡한 타입
using Callback = std::function<void(int)>;
using CallbackList = std::vector<Callback>;
class EventManager {
private:
    CallbackList callbacks;
    
public:
    void subscribe(Callback cb) {
        callbacks.push_back(cb);
    }
    
    void notify(int value) {
        for (auto& cb : callbacks) {
            cb(value);
        }
    }
};
int main() {
    EventManager manager;
    
    manager.subscribe([](int x) {
        std::cout << "Callback 1: " << x << '\n';
    });
    
    manager.subscribe([](int x) {
        std::cout << "Callback 2: " << x * 2 << '\n';
    });
    
    manager.notify(10);
}

멤버 타입 별칭

다음은 cpp를 활용한 상세한 구현 코드입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

template<typename T>
class Container {
public:
    using value_type = T;
    using reference = T&;
    using const_reference = const T&;
    using pointer = T*;
    using size_type = std::size_t;
    
private:
    std::vector<value_type> data;
    
public:
    void push_back(const_reference value) {
        data.push_back(value);
    }
    
    reference operator[](size_type index) {
        return data[index];
    }
    
    size_type size() const {
        return data.size();
    }
};
int main() {
    Container<int> cont;
    cont.push_back(10);
    
    Container<int>::value_type x = cont[0];
    cout << x << endl;
}

네임스페이스 별칭

다음은 cpp를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

namespace very_long_namespace_name {
    class MyClass {
    public:
        void doSomething() {
            cout << "Doing something" << endl;
        }
    };
}
// 네임스페이스 별칭
namespace vln = very_long_namespace_name;
int main() {
    vln::MyClass obj;
    obj.doSomething();
}

자주 발생하는 문제

문제 1: typedef 순서

아래 코드는 cpp를 사용한 구현 예제입니다. 필요한 모듈을 import하고. 코드를 직접 실행해보면서 동작을 확인해보세요.

// ❌ 읽기 어려움
typedef int* (*FuncPtr)(int);
// ✅ using이 더 명확
using FuncPtr = int*(*)(int);

문제 2: 템플릿 별칭

아래 코드는 cpp를 사용한 구현 예제입니다. 필요한 모듈을 import하고. 코드를 직접 실행해보면서 동작을 확인해보세요.

// ❌ typedef는 템플릿 별칭 불가
template<typename T>
typedef std::vector<T> Vec;  // 에러
// ✅ using 사용
template<typename T>
using Vec = std::vector<T>;
Vec<int> numbers = {1, 2, 3};

문제 3: 타입 은닉

아래 코드는 cpp를 사용한 구현 예제입니다. 필요한 모듈을 import하고. 코드를 직접 실행해보면서 동작을 확인해보세요.

// ❌ 타입이 불명확
using IntVec = std::vector<int>;
IntVec vec;  // 실제 타입이 뭐지?
// ✅ 명확한 경우에만 사용
// 자주 사용하거나 복잡한 타입

사용 시기

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// ✅ 사용 권장
// 1. 복잡한 타입
using ComplexType = std::map<std::string, std::vector<int>>;
// 2. 자주 사용하는 타입
using StringVec = std::vector<std::string>;
// 3. 템플릿 별칭
template<typename T>
using Ptr = std::unique_ptr<T>;
// 4. 플랫폼 의존 타입
#ifdef _WIN32
    using FileHandle = HANDLE;
#else
    using FileHandle = int;
#endif
// ❌ 사용 지양
// 1. 간단한 타입
// using Int = int;  // 불필요
// 2. 표준 타입 재정의
// using string = std::string;  // 혼란

typedef vs using 비교

아래 코드는 cpp를 사용한 구현 예제입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// typedef
typedef std::vector<int> IntVec;
typedef int (*FuncPtr)(int);
// using (권장)
using IntVec = std::vector<int>;
using FuncPtr = int(*)(int);
// 장점:
// - 더 읽기 쉬움
// - 템플릿 별칭 지원
// - 일관된 문법

실무 패턴

패턴 1: 플랫폼 추상화

다음은 cpp를 활용한 상세한 구현 코드입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// platform.h
#ifdef _WIN32
    using FileHandle = HANDLE;
    using SocketHandle = SOCKET;
#elif defined(__linux__)
    using FileHandle = int;
    using SocketHandle = int;
#elif defined(__APPLE__)
    using FileHandle = int;
    using SocketHandle = int;
#endif
// 사용
class File {
    FileHandle handle_;
    
public:
    File(const std::string& path);
    ~File();
};

패턴 2: STL 컨테이너 커스터마이징

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <vector>
#include <memory>
// 커스텀 allocator
template<typename T>
using PoolVector = std::vector<T, PoolAllocator<T>>;
// 스마트 포인터 컨테이너
template<typename T>
using PtrVector = std::vector<std::unique_ptr<T>>;
// 사용
PoolVector<int> poolVec;
PtrVector<Widget> widgets;
widgets.push_back(std::make_unique<Widget>());

패턴 3: 콜백 타입

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 클래스를 정의하여 데이터와 기능을 캡슐화하며, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <functional>
#include <map>
#include <string>
// 콜백 타입 정의
using ErrorCallback = std::function<void(const std::string&)>;
using SuccessCallback = std::function<void(int)>;
using ProgressCallback = std::function<void(double)>;
class AsyncTask {
    ErrorCallback onError_;
    SuccessCallback onSuccess_;
    ProgressCallback onProgress_;
    
public:
    void setErrorCallback(ErrorCallback cb) {
        onError_ = cb;
    }
    
    void setSuccessCallback(SuccessCallback cb) {
        onSuccess_ = cb;
    }
    
    void execute() {
        // 작업 수행
        if (/* 에러 */) {
            if (onError_) onError_("에러 발생");
        } else {
            if (onSuccess_) onSuccess_(42);
        }
    }
};

함수 포인터 별칭 (요약)

복잡한 시그니처를 한 줄 이름으로 묶을 때 using이 읽기 쉽습니다.

typedef void (*OldStyle)(int, double);
using NewStyle = void(*)(int, double);  // “이름 = 타입”

멤버 함수 포인터, noexcept 지정, 다양한 호출 규칙까지 섞이면 typedef만으로는 실수하기 쉽습니다. 상세·패턴심화 가이드의 “함수 포인터 타입 별칭” 절을 참고하세요.

템플릿 별칭 (요약)

템플릿 매개변수를 받는 별칭using만 가능합니다. typedef로는 동일한 표현을 할 수 없습니다.

template<typename T>
using Vec = std::vector<T>;

C++11 이전의 template<typename T> struct Vec { typedef std::vector<T> type; }; 같은 우회는 가능하지만 장황하므로, 모던 코드에서는 using이 표준입니다.

가독성·실무에서의 선택

상황권장
새 C++ 코드using
C 공유 헤더·레거시 규칙typedef 유지 가능
템플릿 별칭using 필수
복잡한 함수 포인터using (의도가 오른쪽 타입에 집중됨)
팀 컨벤션에 “항상 using”이 있으면 그에 따르는 것이 리뷰 비용을 줄입니다.

FAQ

Q1: using vs typedef?

A:

  • using: 권장 (C++11 이상), 가독성 높음
  • typedef: 레거시 코드 아래 코드는 cpp를 사용한 구현 예제입니다. 필요한 모듈을 import하고. 코드를 직접 실행해보면서 동작을 확인해보세요.
// typedef: 복잡
typedef void (*FuncPtr)(int);
// using: 간결
using FuncPtr = void(*)(int);

Q2: 언제 타입 별칭을 사용하나요?

A:

  • 복잡한 타입: 가독성 향상
  • 자주 사용하는 타입: 유지보수 용이
  • 템플릿 별칭: 재사용 아래 코드는 cpp를 사용한 구현 예제입니다. 필요한 모듈을 import하고. 코드를 직접 실행해보면서 동작을 확인해보세요.
// 복잡한 타입
using DataMap = std::map<std::string, std::vector<int>>;
// 자주 사용
using StringVec = std::vector<std::string>;
// 템플릿 별칭
template<typename T>
using Ptr = std::unique_ptr<T>;

Q3: 성능 차이는?

A: 없습니다. 타입 별칭은 컴파일 타임에만 영향을 줍니다. 다음은 간단한 cpp 코드 예제입니다. 필요한 모듈을 import하고. 코드를 직접 실행해보면서 동작을 확인해보세요.

// 동일한 코드 생성
std::vector<int> v1;
using IntVec = std::vector<int>;
IntVec v2;

Q4: 템플릿 별칭은?

A: using만 가능합니다. typedef는 불가능합니다. 아래 코드는 cpp를 사용한 구현 예제입니다. 필요한 모듈을 import하고. 코드를 직접 실행해보면서 동작을 확인해보세요.

// ❌ typedef: 불가능
template<typename T>
typedef std::vector<T> Vec;
// ✅ using: 가능
template<typename T>
using Vec = std::vector<T>;

Q5: 네임스페이스 별칭은?

A: namespace alias = original; 을 사용합니다. 아래 코드는 cpp를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

namespace very_long_name {
    class MyClass {};
}
namespace vln = very_long_name;
vln::MyClass obj;

Q6: 타입 별칭과 새 타입의 차이는?

A:

  • 타입 별칭: 기존 타입의 다른 이름 (동일한 타입)
  • 새 타입: enum class, struct (다른 타입) 아래 코드는 cpp를 사용한 구현 예제입니다. 필요한 모듈을 import하고. 코드를 직접 실행해보면서 동작을 확인해보세요.
// 타입 별칭: 동일한 타입
using Int = int;
Int x = 10;
int y = x;  // OK
// 새 타입: 다른 타입
enum class StrongInt : int {};
StrongInt a = StrongInt{10};
// int b = a;  // 에러: 다른 타입

Q7: 멤버 타입 별칭은?

A: 클래스 내부에서 using 을 사용합니다. 아래 코드는 cpp를 사용한 구현 예제입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며. 코드를 직접 실행해보면서 동작을 확인해보세요.

template<typename T>
class Container {
public:
    using value_type = T;
    using reference = T&;
    using const_reference = const T&;
};
Container<int>::value_type x = 10;

Q8: 타입 별칭 학습 리소스는?

A:

  • “Effective Modern C++” by Scott Meyers (Item 9)
  • cppreference.com - Type alias
  • “C++ Primer” by Stanley Lippman 관련 글: typedef, template, auto. 한 줄 요약: 타입 별칭은 기존 타입에 새 이름을 부여하여 가독성과 유지보수성을 높이는 기능입니다.

같이 보면 좋은 글 (내부 링크)

이 주제와 연결되는 다른 글입니다.

관련 글

... 996 lines not shown ... Token usage: 63706/1000000; 936294 remaining Start-Sleep -Seconds 3