객체를 저장하는 객체, 자료구조 라고도 한다. 클래스 템플릿으로 구현되어있다.
Sequence Container vs Associative Container
Sequence Container: array (C++ 11), vector, list, deque
Associative Container : set, multiset, map, multimap
연관 컨테이너에는 고유한 순서가 없다.
- 만약 위의 STL iterator 예제에서 typename 키워드 없이 T::const_iterator pos; 만으로 선언을 했다면,
- 컴파일러는 const_iterator가 T 클래스 내부의 멤버변수일거라고 생각해버릴 수도 있다.
- 아니, 컴파일러는 이런 경우 기본적으로 타입이 아니라고 가정한다.
- 따라서 c++ 컴파일러에게 어떤 키워드는 typedef로 재정의 된 type이라는 것을 알려주기 위해 typename 키워드를 사용해야한다.
- iterator가 vector의 의존타입이기 때문에 iterator가 type이라는걸 알려주기 위해 typename 키워드를 사용해야한다.
- 템플릿 매개변수를 선언하는 경우 class 및 typename을 사용한다.
- typename은 템플릿 내부에서 허용되는 키워드이며,
- 유형 자체가 템플릿 유형 매개변수에 따라 달라지면 그 부유형(subtype)을 참조할 때마다 typename키워드를 붙여야 한다.
- 붙이지 않으면 일반적으로 template에서는 값이라고 인식한다.
class A {
public:
const static int t = 1;
};
class B {
public:
using t = int;
};
template <typename T>
int func() {
T::t* p;
}
func<A>()
func<B>()
T::t* p;
위 문장은 단순히 클래스 A
의 t
와 p
를 곱하는 식으로 해석이 됩니다.
반면에 func
함수가 클래스 B
에 대해서 특수화 된다면,
T::t* p;
이 문장은 int
형 포인터 p
를 선언하는 꼴이 되겠지요.
따라서 컴파일러가 이 두 상황을 명확히 구분하기 위해 저 T::t
가 타입인지 아니면 값인지 명확하게 알려줘야만 합니다.
이렇게 템플릿 인자에 따라서 어떠한 타입이 달라질 수 있는 것을 의존 타입(dependent type) 이라고 부릅니다.
따라서 컴파일러가 성공적으로 해석하기 위해서는 우리가 반드시 "야 저건 는 무조건 타입이야" 라고 알려주어야만 합니다.
typename T::t* p;
ex)
#include <iostream>
class A {
public:
const static int t = 2;
};
class B {
public:
using t = int;
};
template <typename T>
void func() {
typename T::t *p;
std::cout << p << std::endl;
}
template <>
void func<A>() {
int p = 10;
std::cout << A::t *p << std::endl;
}
int main(void) {
A a;
B b;
func<A>();
func<B>();
return (0);
}
template<class _Ty,
class _Container = deque<_Ty> >
class stack
{
// ...
protected:
_Container c; // the underlying container
};
코드를 보면 protected 접근권한자로 _Container 타입의 c 멤버변수가 있고 _Container 타입은 deque<_Ty>와 같다.
따라서, c 멤버변수로는 deque의 함수를 호출할 수 있고 stack을 상속받아 c 변수로 접근가능하다면 deque의 함수들을 사용할 수 있다.