codenuri 강석민 강사 강의 내용기반으로 정리한 내용입니다.
Template Instantiation Technic
Object Generator Idioms 기법
C++17이 나오기 전까지는 클래스 템플릿은 함수 인자를 통해 타입을 추론 할 수 없기 때문에, 클래스 템플릿 사용이 복잡하고 불편하다 -> 함수 템플릿을 만듬
- 클래스 템플릿의 객체를 생성하는 함수 템플릿을 사용한다.
- 함수 템플릿은 함수 인자를 통해 타입을 컴파일러가 추론할 수 있다는 특징을 활용한 기법
- make_pair(), make_tuple()등의 make 계열 함수, STL 삽입 반복 자동
template<typename T> void foo(T a) {}
template<typename T, typename U> struct pair
{
T first;
U second;
pair(const T& a, const U& b): first(a), second(b) {}
};
// 함수 템플릿
template<typename T, typename U>
pair<T, U> make_pair(const T& a, const U& b)
{
return pair<T, U>(a,b);
}
int main() {
pair<int, double> p(1, 3.4);
foo(p);
foo(pair<int, double>(1,3.4)); // 임시객체로 전달...
foo(pair(1, 3.4)); // C++ 17
foo(make_pair(1,3.4));
// foo(tuple<int, double, int>(1, 3.4, 1));
// foo(make_tuple(1, 3.4,1));
}
Identity 기법
- 함수 템플릿 사용시 컴파일러에 의한 타입 추론을 막는 테크닉
- 함수 템플릿 사용시 사용자가 반드시 타입을 전달하도록 하고 싶을 때
- 컴파일러에 의한 타입 추론이 원하지 않은 타입으로 추론되는 경우
template<typename T> struct identity
{
typedef T type;
};
template<typename T> void foo(T a) {}
template<typename T> void goo(typename identity<T>::type a) {}
// T 타입이라 foo랑 같을까?
int main() {
identity<int>::type n; // int
foo(3); // ok 함수템플릿이므로 컴파일러가 추론해서 가능
foo<int>(3); // ok
goo(3); // identity는 클래스 템플릿이므로 3을 가지고 클래스 템플릿추론 불가(C++17이라도 생성자나 가이드가 없어 추론 불가) -> 컴파일 타임 error
goo<int>(3); // ok
}
template instantiation 주의사항
- square는 함수가 아닌 함수 템플릿, square
가 함수
#include <iostream>
using namespace std;
template<typename T> T square(T a)
{
return a * a;
}
int main()
{
// printf("%p\n", &square); // error 템플릿은 틀이니까
printf("%p\n", &square<int>); // ok 이렇게 적으면 인스턴스화 시킴
printf("%p\n", static_cast<int(*)int>(&square)); // ok
// auto p = □ // error
auto p1 = &square<int>; // ok
auto p2 = static_cast<int(*)(int)>(&square); // ok
}
템플릿과 다중파일
Lib.h
int add (int a, int b);
template<typename T> T square(T a);
Lib.cpp
int add(int a, int b)
{
return a+b;
}
template<typename T> T square(T a)
{
return a*a;
}
main.cpp
#include "Lib.h"
int main()
{
add(1,2);
square(3);
}
템플릿은 소스에 제공하는 것이 아니라 헤더에 제공하는 것임(위 처럼하면 error)
template 은 틀이고 cpp은 파일별로 분할해서 컴파일함 Lib.h 만 포함되어 있으니 컴파일러는 헤더만 보고 square의 정의부분이 없어 코드 생성을 못해 error 발생
해결책
선언쪽에 template을 구현해야함
Lib.h
int add (int a, int b);
template<typename T> T square(T a)
{
return a*a;
}
Lib.cpp
int add(int a, int b)
{
return a+b;
}
main.cpp
#include "Lib.h"
int main()
{
add(1,2);
square(3);
}