템플릿
2025. 3. 28. 08:47ㆍProgramming Languages/C++
템플릿
템플릿은 C++의 가장 강력한 기능 중 하나로, 타입에 독립적인 코드를 작성할 수 있게 해줍니다. 템플릿을 사용하면 다양한 데이터 타입에 대해 동일한 알고리즘이나 클래스를 하나의 코드로 구현할 수 있어, 코드 재사용성과 유지보수성을 크게 향상시킬 수 있습니다.
7.1 함수 템플릿 기초
7.1.1 함수 템플릿의 개념
함수 템플릿은 다양한 데이터 타입에 대해 동작하는 함수의 "청사진"을 정의합니다. 실제 함수는 컴파일러가 템플릿으로부터 필요한 타입에 맞게 생성합니다.
#include <iostream>
// 두 값 중 최대값을 반환하는 함수 템플릿
template <typename T>
T max(T a, T b) {
return (a > b) ? a : b;
}
int main() {
// 정수형에 대한 호출
int iResult = max(10, 20);
std::cout << "정수 최대값: " << iResult << std::endl;
// 실수형에 대한 호출
double dResult = max(3.14, 2.71);
std::cout << "실수 최대값: " << dResult << std::endl;
// 문자형에 대한 호출
char cResult = max('A', 'Z');
std::cout << "문자 최대값: " << cResult << std::endl;
return 0;
}
위 코드에서:
- template <typename T>: 템플릿 선언, T는 타입 매개변수
- typename과 class 키워드 모두 타입 매개변수를 정의하는 데 사용할 수 있습니다.
- 함수를 호출할 때, 컴파일러는 인수의 타입에 따라 적절한 함수 버전을 생성합니다.
7.1.2 템플릿 타입 추론
컴파일러는 함수 호출 시 전달된 인수의 타입을 기반으로 템플릿 매개변수의 타입을 자동으로 추론합니다:
#include <iostream>
#include <string>
template <typename T>
void showType(T value) {
// typeid는 type_info 객체를 반환
std::cout << "값: " << value << ", 타입: " << typeid(T).name() << std::endl;
}
int main() {
showType(42); // T는 int로 추론
showType(3.14159); // T는 double로 추론
showType("Hello"); // T는 const char*로 추론
showType(std::string("World")); // T는 std::string으로 추론
return 0;
}
7.1.3 명시적 템플릿 인수
함수 호출 시 템플릿 타입을 명시적으로 지정할 수도 있습니다:
#include <iostream>
template <typename T>
T max(T a, T b) {
return (a > b) ? a : b;
}
int main() {
// 명시적 타입 지정
std::cout << max<int>(10, 20) << std::endl;
std::cout << max<double>(3.14, 2.71) << std::endl;
// 타입 변환을 통한 혼합 타입 사용
std::cout << max<double>(10, 3.14) << std::endl; // 10은 double로 변환됨
return 0;
}
7.1.4 여러 템플릿 매개변수
함수 템플릿은 여러 타입 매개변수를 가질 수 있습니다:
#include <iostream>
#include <string>
// 두 개의 타입 매개변수를 가진 함수 템플릿
template <typename T1, typename T2>
void printPair(T1 a, T2 b) {
std::cout << "첫 번째 값(" << typeid(T1).name() << "): " << a << std::endl;
std::cout << "두 번째 값(" << typeid(T2).name() << "): " << b << std::endl;
}
// 두 개의 서로 다른 타입을 처리하는 함수 템플릿
template <typename T1, typename T2>
auto add(T1 a, T2 b) -> decltype(a + b) {
return a + b;
}
int main() {
printPair(42, "Hello"); // T1=int, T2=const char*
printPair(3.14, std::string("Pi")); // T1=double, T2=std::string
// 다른 타입의 덧셈
auto result1 = add(5, 3.14); // int + double = double
auto result2 = add(std::string("Hello, "), "World"); // std::string + const char* = std::string
std::cout << "result1: " << result1 << std::endl;
std::cout << "result2: " << result2 << std::endl;
return 0;
}
여기서 decltype(a + b)는 식 a + b의 타입을 추론하여 함수의 반환 타입으로 사용합니다. 후행 반환 타입(trailing return type) 구문 -> 타입은 C++11에서 도입되었습니다.
7.1.5 템플릿 특수화
특정 타입에 대해 다른 구현을 제공하고 싶을 때 템플릿 특수화를 사용할 수 있습니다:
#include <iostream>
#include <string>
// 일반 템플릿
template <typename T>
void printInfo(const T& value) {
std::cout << "일반 템플릿: " << value << std::endl;
}
// char* 타입에 대한 특수화
template <>
void printInfo<char*>(char* const& value) {
std::cout << "문자열 특수화: " << value << " (길이: " << strlen(value) << ")" << std::endl;
}
// const char* 타입에 대한 특수화
template <>
void printInfo<const char*>(const char* const& value) {
std::cout << "상수 문자열 특수화: " << value << " (길이: " << strlen(value) << ")" << std::endl;
}
// std::string 타입에 대한 특수화
template <>
void printInfo<std::string>(const std::string& value) {
std::cout << "std::string 특수화: " << value << " (길이: " << value.length() << ")" << std::endl;
}
int main() {
int num = 42;
printInfo(num); // 일반 템플릿 사용
char str[] = "Hello";
printInfo(str); // char* 특수화 사용
const char* cstr = "World";
printInfo(cstr); // const char* 특수화 사용
std::string sstr = "C++ Templates";
printInfo(sstr); // std::string 특수화 사용
return 0;
}
템플릿 특수화는 일부 타입에 대해 최적화된 구현이나 특별한 처리가 필요할 때 유용합니다.
7.1.6 함수 템플릿 오버로딩
함수 템플릿은 일반 함수와 마찬가지로 오버로딩할 수 있습니다:
#include <iostream>
// 하나의 매개변수를 가진 템플릿
template <typename T>
void print(T value) {
std::cout << "단일 값: " << value << std::endl;
}
// 두 개의 매개변수를 가진 템플릿
template <typename T>
void print(T value1, T value2) {
std::cout << "두 값: " << value1 << ", " << value2 << std::endl;
}
// 다른 타입의 두 매개변수를 가진 템플릿
template <typename T1, typename T2>
void print(T1 value1, T2 value2) {
std::cout << "서로 다른 타입의 두 값: " << value1 << ", " << value2 << std::endl;
}
// 비템플릿 함수 (일반 함수)
void print(int value) {
std::cout << "특수한 int 처리: " << value << std::endl;
}
int main() {
print(42); // 일반 함수 호출 (더 특수한 버전이 우선)
print(3.14); // 템플릿 print<double>(T)
print(10, 20); // 템플릿 print<int>(T, T)
print(10, 3.14); // 템플릿 print<int, double>(T1, T2)
print<double>(42); // 명시적으로 템플릿 print<double>(T) 호출
return 0;
}
함수 오버로딩 해결 규칙:
- 일치하는 비템플릿 함수(일반 함수)를 찾습니다.
- 일치하는 특수화된 템플릿 함수를 찾습니다.
- 가장 특수화된(가장 구체적인) 함수를 선택합니다.
- 모호한 경우 컴파일 오류가 발생합니다.
'Programming Languages > C++' 카테고리의 다른 글
| 비타입 템플릿 매개변수 (0) | 2025.03.28 |
|---|---|
| 클래스 템플릿 기초 (0) | 2025.03.28 |
| 챕터6. 실습 문제 (0) | 2025.03.28 |
| 고급 포인터 주제 (0) | 2025.03.28 |
| 참조 (0) | 2025.03.28 |