[ Effective C++ ] 항목 42 : typename의 두 가지 의미를 제대로 파악하자

Minsu._.Lighting·2023년 12월 11일
0


[ Effective C++ ] 정리 모음집
" C++ 프로그래머의 필독서, 스콧 마이어스의 Effective C++ 를 읽고 내용 요약 / 정리 "

[핵심]

" 템플릿 사용 시 typename을 사용해야 하는 경우를 정확히 인지하고 사용하자! "

  • 템플릿 매개변수를 선언할 때, class 및 typename은 서로 바꾸어 써도 무방하다!
  • 중첩 의존 타입 이름을 식별하는 용도에는 반드시 typename을 사용하자! 단, 중첩 의존 이름이 기본 클래스 리스트에 있거나 멤버 초기화 리스트 내의 기본 클래스 식별자로 있는 경우에는 예외!

💡 템플릿 선언문에서의 class와 typename의 차이점

template<class T> class Widget;
template<typename T> class Widget;
  • 위 두 템플릿 언언문에 쓰인 class와 typename은 차이가 없다!
    - 템플릿의 타입 매개변수를 선언할 때는 class와 typename의 뜻이 완전 똑같다

[ 템플릿 선언문에서 class와 typename을 사용 하는 프로그래머들 ]

  • class가 typename보다 타이핑 수가 줄어들어 class만을 사용 하는 프로그래머들도 있다
  • 매개변수가 class일 필요가 없다고 외치는듯한 모습에 typename을 선호하는 프로그래머들도 있다
  • 어떠한 타입도 허용되는 부분에는 typename을, 사용자 정의 타입만 쓰이는 부분에는 class를 쓰는 프로그래머들도 있다

"마음대로 쓰자!"



💡 typename을 사용 해야만 할 때

template<typename C>
void print2nd(const C& container)
{
	if(container.size() >= 2)
    {
    	C::const_iterator iter(container.begin());
        
        ++iter;
        int value = *iter;
        cout << value;
    }
}

📌 의존 이름 비의존 이름

  • 템플릿 내의 이름 중 템플릿 매개변수에 종속된 것 을 가리켜 의존 이름 이라고 한다
    C::const iterator
    - C가 무엇인지에 따라 타입이 달라진다.

📢 의존 이름이 클래스 안에 중첩되어 있는 경우가 있는데 이를 중첩 의존 타입 이름 이라고 한다!

  • 템플릿 내의 이름 중 매개변수가 어떻든 상관 없는 타입 이름을 비의존 이름이라고 한다.
    int value;

📌 중첩 의존 타입 이름 때문에 발생하는 문제

template<typename C>
void print2nd(const C& container)
{
	C::const_iterator* x;
    ...
}
  • 다음과 같은 문제가 발생할 수 있음
    • C::const_iterator가 타입이 아니라면?
    • 우연히 const_iterator라는 이름을 가진 정적 데이터 멤버가 C에 들어있었다면?
    • x가 다른 전역 변수의 이름이라면?

    📢 " C::const_iterator와 x를 피연산자로 한 곱셈 연산이 수행 될 수 있다!! "
    const_iterator * x

- C++은 모호성을 해결하기 위해 구문 분석기가 템플릿 안에서 중첩 의존 타입 이름을 만나면 그 이름이 타입이 아니라고 가정하는 규칙을 사용 함

  • typename키워드를 이용해 어떤 타입인지 알려주자!
template<typename C>
void print2nd(const C& container)
{
	if(container.size() >= 2)
    {
    	typename C::const_iterator iter(container.begin());
        ...
    }
}

📌 typename 키워드는 중첩 의존 타입 이름만 식별하는 데 사용 해야 한다!

template<typename C>					// typename 사용 가능(선언부 이므로 class와 같은 의미)
void f(const C& contanier,				// typename 쓰면 안 됨
		typename C::iterator iter);		// typename 필수 사용
  • const C& container 는 의존 이름이지 중첩 의존 타입 이름이 아니다!

📢 typename은 중첩 의존 타입 이름 앞에 붙여 주어야 한다는 규칙에 예외 사항

template<typename T>
class Derived : public Base<T>::Nested		// typename 쓰면 안 됨(상속되는 기본 클래스 리스트)
{
public:
	explicit Derived(int x)
    : Base<T>::Nested(x)					// typename 쓰면 안 됨(초기화 리스트 내 기본 클래스 식별자)
    {
    	typename Base<T>::Nested temp;		// typename 필수 사용(중첩 의존 타입 이름)
        ...
    }
    ...
};
  • 중첩 의존 타입 이름이 기본 클래스의 리스트에 있거나 멤버 초기화 리스트 내의 기본 클래스 식별자로서 있을 경우에는 사용 하면 안된다.

📌 현업 코드에서 많이 보이는 typename의 대표적 사례

template<typename IterT>
void workWithIterator(IterT iter)
{
	typedef typename std::iterater_traits<IterT>::value_type value_type;
    
    value_type temp(*iter);
    ...
}
  • typedef 와 typename이 같이 있어 어색할 수 있으나 규칙과 논리적으로 하자가 없는 코드
    - 어색하다 쳐도 typedef 없이 typename std::iterator_traits::value_type을 몇 번까지 또박또박 칠 수 있을 것 같은지...?


💡 그 외 typename에 관한 이야기...

  • typename에 관한 규칙은 컴파일러마다 조금씩 차이가 있다
    - typename과 중첩 의존 타입 이름 사이에는 이러한 이유로 프로그램을 이식할 때 다소 골치가 아파질 수 있다!
profile
오코완~😤😤

0개의 댓글

관련 채용 정보