2022. 3. 25. 20:06ㆍC++
템플릿 템플릿 파라미터(Template Template Parameter)란, 템플릿 인자로 class template 또는 alias template을 전달할 수 있게하는 langauage feature이다.
템플릿 인자로 class template/alias template을 전달해서 어디에 쓰이는지 알아보기 위해 다음 코드를 보자.
template <typename T, typename Container>
class Stack
{
private:
Container m_Container;
public:
// You can use forwarding reference for the better performance
void Push(T const& value);
// Some member functions
// ...
};
int main()
{
// the element type 'int' is specified twice
Stack<int, std::deque<int>> stack;
}
위 Stack 클래스 템플릿은 내부 구현에 사용될 컨테이너를 템플릿 파라미터(Container)로 받고있다.
하지만, main 함수 내에서 Stack 템플릿 클래스를 인스턴스화 할 때 요소(Element) 타입이 두 번 명시되는 것을 볼 수 있다. 멤버 함수의 파라미터로 사용되는 템플릿 파라미터 T와 컨테이너 요소 타입은 대부분 일치 할 것이기에, 이렇게 두 번 명시하는 경우를 피하고 싶을 것이다.
이럴 때 템플릿 템플릿 파라미터를 사용하여 Container 템플릿 인자로 요소가 명시된 템플릿 클래스 대신에 클래스 템플릿을 전달한다. 다음 코드를 보자.
template <typename T,
template <typename>
class Container = std::deque>
class Stack
{
private:
Container<T> m_Container;
public:
// You can use forwarding reference for the better performance
void Push(T const& value);
// Some member functions
// ...
};
int main()
{
Stack<int, std::deque> stack;
}
template <typename T, template <typename> ..> 이 부분을 보면 왜 템플릿 템플릿 파라미터인지 알 수 있을 것이다.
이제 Stack<int, std::deque>와 같이 요소 타입을 한 번만 명시해도 되며, 클래스 템플릿을 인자로 전달한다.
위 코드를 Clang 컴파일러에서 실행하면 다음과 같은 컴파일 에러가 뜬다.
(MSVC/GCC에서는 정상적으로 컴파일 된다.)
error: template template argument has different template parameters than its corresponding template template parameter
템플릿 템플릿 인자 std::deque가 대응되는 템플릿 템플릿 파라미터 Container와 다른 템플릿 파라미터들을 가지고 있다고 말하고 있다.
이 문제는 std::deque가 요소 타입 외 Allocator라는 템플릿 파라미터를 가지고 있기 때문에 발생한다.
이 Allocator 템플릿 파라미터는 템플릿 인자가 디폴트로 할당되어 있는데, 따라서 MSVC/GCC 컴파일러는 이 인자에 대해 신경쓰지 않아도 되는 반면에, Clang은 아직 지원되지 않는 듯 하다.
해결 방법은 아래 코드와 같이 2가지가 있다.
template <typename T,
template <typename Elem, typename = std::allocator<Elem>>
class Container = std::deque>
template <typename T,
template <typename...>
class Container = std::deque>
참고로 C++17부터는 템플릿 템플릿 파라미터를 선언할 때 typename 또는 class 둘 중 어느 것을 사용해도 상관없다.
(C++14에서도 MSVC/Clang/GCC 모두 Compiler Explorer에서 작동하긴 하는데, Clang/GCC에서는 typename을 사용했을 때 C++17 확장 기능이라고 경고를 준다.)
template <typename T,
template <typename>
class Container = std::deque> // OK
template <typename T,
template <typename>
typename Container = std::deque> // OK
[참고]
- C++ Templates: The Complete Guide, 2nd Edition
'C++' 카테고리의 다른 글
문자열 리터럴을 템플릿 인자로 전달하는 방법 (0) | 2022.04.02 |
---|---|
Literal Class Type as Non-type Template Parameter (0) | 2022.04.02 |
.template / ::template / ->template (0) | 2022.03.23 |
클래스 템플릿에 선언된 friend 함수를 외부에 정의하는 방법 (0) | 2022.03.21 |
The Complete Guide to return x; - Implicit Move (0) | 2022.03.13 |