On this page
article
C++ Template Basic
템플릿 디버깅
템플릿 인스턴스화 결과 확인
- 어셈블리 확인: godbolt.org
- C++ 원리 확인: cppinsights.io

인스턴스화된 함수 이름 출력
__FUNCTION__
: 함수 이름만 출력 (표준 매크로)__FUNCSIG__
: 함수 시그니처 포함 (비표준, MSVC 전용)__PRETTY_FUNCTION__
: 함수 시그니처 포함 (비표준, g++, clang)std::source_location
: C++20부터 지원
#include <source_location>
std::source_location s = std::source_location::current();
템플릿 구현
템플릿과 파일 분할
- 템플릿은 헤더파일에 구현해야 함.
- 구현부가 다른 파일에 있으면 컴파일 실패.
함수 템플릿과 오버로딩
// 기본 함수
int square(int a) { return a * a; }
// 함수 템플릿
template<typename T>
T square(T a) { return a * a; }
// 호출 예시
square<int>(3); // 명시적 인스턴스화
square(3); // 타입 추론
타입에 따라 다른 구현 (requires)
template<typename T>
requires std::integral<T>
T square(T a) { return a * a; }
템플릿 인자가 2개인 경우
- 반환타입 표기법:
auto + decltype
type_traits
의std::common_type
- C++20에서는 all auto 사용 가능
// C++11
template<typename T1, typename T2>
auto add(const T1& a, const T2& b) -> decltype(a + b)
{
return a + b;
}
// C++11 - type_traits
template<typename T1, typename T2>
typename std::common_type<T1, T2>::type add(const T1& a, const T2& b)
{
return a + b;
}
// C++20
auto add(const auto& a, const auto& b)
{
return a + b;
}
템플릿 생성 (C++20)
C++20부터는 template
auto square(auto a) { return a * a; }
클래스 템플릿
- 클래스 템플릿도 헤더파일에 구현해야 함.
template<typename T>
class Point
{
T x, y;
public:
Point(T a, T b) : x(a), y(b) {}
};
template static 멤버 변수
다음과 같이 외부에서 따로 초기화 진행
template<typename T1, typename T2>
struct Object
{
T1 first;
T2 second;
static int cnt;
}
template<typename T1, typename T2>
int Object<T1, T2>::cnt = 0; // non-const static member in-class initialization
추가 템플릿 종류
Member Template
- 멤버 함수를 템플릿으로 만드려면 클래스 안에 template표기 넣어서 만들어야함
- 외부에 구현하면 모양이 조금 복잡
template<typename T>
struct Object
{
void mf1(T n) {}
template<typename U>
void mf2(U n) {}
}
// 외부 구현 시
template<typename T> template<typename U>
void Object<T>::mf2(U n) {}
필요성
- Coercion by Member Template
- T가 U로 복사(대입) 가능하다면, Point<T>도 Point<U>로 복사(대입) 가능해야한다.
- 다른 타입 객체의 멤버에 접근하기 위해 friend도 필요
- Point는 template 인자가 한개인 애인데 애들끼리 다 friend
- 타입에 대한 제한도 필요하므로 requires is_convertible_v<U, T> 사용
template<typename T>
class Point
{
T x, y;
public:
Point(const T& a, const T& b): x(a), y(b)
template<typename U>
requires std::is_convertible_v<U, T>
Point(const Point<U>& p): x(p.x), y(p.y) {
template<typename> friend class Point;
}
}
int main()
{
Point<std:;string> p1("1", "2");
Point<int> p2 = p1;
}
Variable Template (C++14)
- 예시
template<typename T> constexpr T pi = static_cast<T>(3.141592); int main() { double area1 = 3*3*pi<double>; }
- 필요성
- template specialization과 같이 사용
- type_traits 구현의 핵심
- STL 구현에 다양하게 활용
Using Template (C++11)
- 예시
- 위쪽 대신 아래쪽으로 활용가능
using SET = std::unordered_set<int>; using SETD = std::unordered_set<double>; template<typename T> using SET = std::unorderd_set<T>;
lazy instantiation
- 개념
- 클래스 템플릿의 멤버함수는 사용된 것만 인스턴스화 됨
- 그래서 사용안한 함수에 에러가 있어도 컴파일
- 재밌는 사례
- queue 구현 시 vector는 pop_front()가 없기에 사용하면 안되는데 실제로 사용해도 pop()을 쓰기 전 까지는 에러가 안 남
- static member
- static도 마찬가지로 규칙을 적용받음
class template & friend
- 문제
- operator «를 friend로 등록해놓고 외부에 구현해놓으면 Instantiate될 때 (예를 들어 int) operator« (os, const Point
& pt) 버전이 딸려들어감 - 이러면 외부에 구현된 템플릿화된 operator«와 연결되지않아서 에러
- friend함수를 그냥 안에 구현하면 해결
- 외부함수로 쓰려면 다른 템플릿 변수 활용해 템플릿 함수로 만듬
- operator «를 friend로 등록해놓고 외부에 구현해놓으면 Instantiate될 때 (예를 들어 int) operator« (os, const Point
template<typename T>
class Point
{
T x, y;
public:
Point(T a, T b) : x(a), y(b) {}
// 아래와 같이 선언만 해두면 문제 상황 발생
// friend std::ostream& operator<<(std::ostream& os, const Point<T>& pt)
friend std::ostream& operator<<(std::ostream& os, const Point<T>& pt)
{
std::cout << pt.x << ", " << pt.y << std::endl;
return os;
}
}
template<typename T>
std::ostream& operator<<(std::ostream& os, const Point<T>& pt)
{
std::cout << pt.x << ", " << pt.y << std::endl;
return os;
}