무민은귀여워

typedef 보다 별칭 선언을 선호하라 본문

IT/c, c++

typedef 보다 별칭 선언을 선호하라

moomini 2020. 1. 17. 16:56
반응형

typedef와 별칭 선언이 하는 일은 정확히 동일하다. 

 

별칭 선언의 예

1
2
3
4
5
6
7
8
9
// typedef 를 사용한 옛 버전
typedef
    std::unique_ptr<std::unordered_map<std::stringstd::string>>
    UPtrMapSS;
 
 
// 별칭 선언 (alias declaration)
using UPtrMapSS =
std::unique_ptr<std::unordered_map<std::stringstd::string>>;
cs

 

그러나 typedef보다 별칭 선언을 선호하는 이유는 다음과 같다.

 

  1. 함수 포인터가 관여하는 형식을 다룰 때는 별칭 선언 쪽을 더 쉽게 이해하는 사람들이 많다
  2. typedef는 템플릿화할 수 없지만 별칭 선언은 템플릿화 할 수 있다. 템플릿화된 별칭 선언을 별칭 템플릿(alias templates)이라고 부른다.

1의 예

1
2
3
4
5
6
7
// FP는 int 하나와 const std::string& 하나를 받고
// 아무것도 돌려주지 않는 함수와 동의어이다
typedef void (*FP)(intconst std::string&); // typedef
 
 
// 위와 같은 의미
using FP = void (*)(intconst std::string&); // 별칭 선언
cs

 

2의 예

MyAlloc이라는 커스텀 할당자(alloator)를 사용하는 연결 목록(linked list)의 동의어를 정의한다고 하자. 별칭 템플릿을 이용하면 식은 죽 먹기이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// typedef 를 사용한 옛 버전
template<typename T>                            // MyAllocList<T>::type은
struct MyAllocList {                            // std::list<T, MyAlloc<T>> 와 동의어이다
    typedef std::list<T, MyAlloc<T>> type;
};
 
MyAllocList<Widget>::type lw;                    // 클라이언트 코드
 
 
// 별칭 선언 (alias declaration)
template<typename T>                            // MyAllocList<T>은
using MyAllocList = std::list<T, MyAlloc<T>>;    // std::list<T, MyAlloc<T>> 와 동의어이다
 
MyAllocList<Widget> lw;                            // 클라이언트 코드
cs

템플릿 매개변수로 지정된 형식의 객체들을 담는 연결 목록을 생성하려는 목적으로 템플릿 안에서 typedef를 사용하려 한다면, typedef 이름 앞에 typename을 붙여야 한다.

 

이 예에서 MyAllocList<T>::type은 템플릿 형식 매개변수(T)에 의존적인 형식을 지칭한다. 즉 MyAllocList<T>::type은 소위 의존적 형식(dependent type)이며, c++의 여러 규칙 중 하나는 의존적 형식의 이름 앞에 반드시 typename을 붙여야 한다는 것이다.

 

MyAllocList를 별칭 템플릿으로 정의하면 typename을 붙일 필요가 없다(또한, 번거로운 "::type" 접미어도 붙일 필요가 없다.)

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// typedef 를 사용한 옛 버전
template<typename T>
class Widget {                                    // Widget<T>에는
private:                                        // MyAllocList<T> 형식의 자료 멤버가 있다
    typename MyAllocList<T>::type list;
};
 
 
// 별칭 선언 (alias declaration)
template<typename T>
using MyAllocList = std::list<T, MyAlloc<T>>;    // 이전과 동일
 
template<typename T>
class Widget {
private:
    MyAllocList<T> list;                        // "typename" 없음
    ...                                            // "::type" 없음
};
cs

컴파일러가 Widget 템플릿을 처리하는 과정에서 MyAllocList<T>가 쓰인(즉, 별칭 템플릿의 용례) 부분에 도달했을 때, 컴파일러는 그 MyAllocList<T>가 형식의 이름임을 이미 알고 있다. MyAllocList가 형식 템플릿이므로 MyAllocList<T>는 반드시 형식의 이름이어야 하기 때문이다.

 

즉, MyAllocList<T>는 비의존적 형식(non-dependent type)이며, 따라서 typename 지정자를 붙일 필요가 없고 붙여서도 안 된다.

 

반면, Widget 템플릿 안에서 MyAllocList<T>::type(즉, 내포된typedef의용례)을 만난 컴파일러는 그것이 형식의 이름임을 확신하지 못한다. 왜냐하면 MyAllocList의 어떤 특수화(specialization)에서 MyAllocList<T>이 형식 이외의 어떤 것을 지칭할 가능성이 남아 있기 때문이다.

반응형
Comments