C, C++/C++ 언어 / / 2024. 7. 22.

[C++] 별명을 만드는 typedef와 using

typedef와 using을 사용하는 이유

typedef와 using은 타입의 별명( alias )을 만드는 데 사용되는 키워드입니다.

예를 들면, 아래의 코드는 int 타입을 DataType으로 바꿔서 사용할 수 있게 됩니다.

using DataType = int;

DataType arr[100];	// 실제로는 int형 배열 선언

 

이러한 키워드들을 사용해서 별명( alias )을 만듦으로써 다양한 편리함을 얻을 수 있습니다.

  • 플랫폼 독립적인 코드 작성을 위해서
  • 복잡한 타입을 읽고 쓰기 쉽도록 만들기 위해
  • 값의 의미를 문서화하기 위해서
  • 코드 유지보수를 쉽게 하기 위해서

 

typedef가 초창기 때부터 사용되어 온 것이라면, using은 tydedef를 불편함을 보완하기 위해 도입된 키워드라고 볼 수 있습니다.

 

typedef 키워드의 문제점

별명을 만드는 데 사용되어 오던 typedef는 몇 가지 사용 상의 불편함을 가지고 있었습니다.

그래서 typedef는 과거에 작성된 코드들과의 호환성 문제 때문에 유지는 하지만, modern C++ 에선 using 키워드를 권장합니다.

선언 순서의 불일치

첫 번째, typedef의 문제점은 선언 시, 순서가 혼동된다는 것입니다.

#define DataSize	100	// define 구문

typedef DataType 	int;	// 잘못된 선언

typedef int	DataType;	// ok

첫 번째 typedef 구문은 #define 구문과 유사합니다.

그러나, 두 번째 줄은 별명 선언의 순서가 바뀌었습니다.

물론, 컴파일러가 경고를 해주지만, 무의식적으로 사용하다 보면 한 번씩 잘못 입력하는 자신을 볼 수 있습니다.

그리고, 변수에 값을 대입하는 구문과도 혼동을 일으킵니다.

int DataSize = 100;	// 대입 구문

 

하지만, using은 이해하기 쉬운 구문을 사용합니다.

using DataType = int;	// 대입 구문와 일치

 

별명의 위치 

함수 포인터의 별명을 typedef를 사용해 선언 시, 별명의 위치 때문에 인식하기가 어렵다는 것을 알게 됩니다.

bool CompareFunc( const int& a, const int& b){ /*... */ }

typedef bool (*FcnType)( const int&, const int&);	// 인식하기 어려움

위에서 보다시피, 별명이 문자의 중간에 파묻혀 있습니다.

매개 변수와 리턴 값의 타입과 별명을 구분하기 위해, 불필요한 집중을 해야 합니다.

 

그렇지만, using을 사용하면 구문이 말하고자 하는 것을 한 번에 알 수 있습니다.

별명과 함수 선언 부분이 = 으로 완전히 분리되어 있습니다.

using FunType = bool(*)( const int&, const int&);	// 구문을 읽기 쉬움

 

의미의 모호성

typedef는 처음 접할 때, struct나 class처럼 새로운 타입을 정의하는 것으로 받아들일 수 있습니다.

그러나, 타입을 정의하는 것과는 아주 동떨어져 있습니다.

단지, 별명( aliases )을 선언하는 것일 뿐입니다.

 

using에서는 그러한 모호성을 느끼기 어렵습니다.

 

template 지원

typedef 구문에선 template를 사용할 수 없습니다.

그래서, int 타입의 std::set을 선언할 때, 원소를 정렬하는 사용자 함수를 사용하려면 다음과 같이 선언해야 합니다.

template<typename T>
bool comp( const T& a, const T& b){	// 원소를 비교하는 사용자 함수
    return a > b;
}

// 비교 함수 타입의 별명으로 선언을 간소화
// 그러나, typedef는 template를 지원하지 못합니다.
typedef bool(*FcnType)(const int&, const int&);

std::set< int, FcnType > s(comp<int>);

 

만약, double이나 char 타입의 set을 선언하려면, typedef 구문을 그 수만큼 더 작성해야 합니다.

typedef bool(*FcnType)(const double&, const double&);	// double 타입 비교 함수

std::set< int, FcnType > s(comp<double>);

 

그렇지만, using 구문에서는 template를 사용할 수 있습니다.

template<typename T>
using FcnType = bool(*)(const T&, const T&);	// template 지원

std::set< int, FcnType<int> > s(comp<int>);

여기서, std::set의 두 번째 형식 템플릿 매개변수에, 원소를 비교할 때 사용될 함수 객체의 타입을 지정해야 합니다.

그리고, 이러한 set 타입의 객체를 생성하기 위해서, 구체적으로 사용할 함수 객체를 받는 생성자로 초기화합니다.

 

참고로, 클래스나 구조체 템플릿을 사용하여, 형식 템플릿 매개변수를 적용하는 typedef 별칭을 만드는 방법도 있습니다.

template< typedef T >
struct MyCompareFcn{
    typedef bool (*type)(const T&, const T&);
};

std::set< int, MyCompareFcn<int>::type > s( comp<int> );

MyCompareFcn 구조체 안에서, typedef를 사용하여 비교할 함수의 타입의 별명을 설정하고 있습니다.

 

 

  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유