-
_C++_TemplateProgramming/_C++ 2023. 9. 24. 23:20
템플릿은 C++ 의 일반화된 코드를 남드는 강력한 도구이다.
대상에 대한 타입만 다르고 로직이 다르지 않다면 템플릿으로 단순한 반복 작업으로 함수나 클래스를 만들 수 있다.
예를 들어 int type에 대한 더하기 함수, double type에 대한 더하기 함수 두가지가 있다면, 템플릿으로 형태를 만들어서 두 형식의 함수를 만들 수 있다.
기본적인 구조는 다음과 같다.
template<typename T> class Samlple { Sample(const Sample<T>& src) = default; //const Sample<T>&는 파라미터 타입의 예시 //... }; //함수 템플릿 template<typename T> void f(const T& param); //const T&는 파라미터 타입의 예시
T는 아직 정해지지 않는 타입이며, T는 컴파일시 타입을 추론한다.
함수 템플릿 예시를 보면 다음과 같다.
#include <iostream> using namespace std; template <typename T> T sum(T a, T b){ // T는 아직 정해지지 않은 type return a + b; } int main(){ int a = 3, b = 5; cout << a + b << "\n"; // 8 double c = 3.2, d = 5.1; cout << c + d << "\n"; // 8.3 return 0; }
컴파일하는 순간 일련의 알고리즘으로 T가 무엇인지 추론하는데, 이는 auto 타입의 추론과 유사하다.
템플릿 클래스나 템플릿 함수가 인스턴스화 되는 시점에 컴파일러는 그 구현부를 볼 수 있어야 하므로 템플릿의 정의는 헤더 파일에 들어가야한다. 관례적으로 이렇게 템플릿 정의가 포함된 헤더파일의 확장자를 hpp로 사용한다.
보충 내용: 템플릿 파라미터 팩, 논타입 템플릿 파라미터, 템플릿 템플릿 파라미터
템플릿 파라미터는 한 번에 여러 개의 파라미터가 올 수 있게 만들 수 있다.
템플릿 파라미터 팩을 사용하면 개수의 제한이 없이 파라미터를 정의할 수 있다.
#include<cstdio> #include<chrono> template<typename Func, typename... Params> // 템플릿 팩을 사용하여 여러 개의 파라미터를 정의하는 모습. auto runAndReturnElapsedTime(Func&& function, Params&&... params) { auto start = std::chrono::high_resolution_clock::now(); std::forward<decltype(function)>(function)(std::forward<decltype(params)>(params)...); return (std::chrono::high_resolution_clock::now() - start).count(); } auto runAndReturnElapsedTime2 = [](auto&& function, auto&&... params) { auto start = std::chrono::high_resolution_clock::now(); std::forward<decltype(function)>(function)(std::forward<decltype(params)>(params)...); return (std::chrono::high_resolution_clock::now() - start).count(); }; int main() { auto times = runAndReturnElapsedTime(printf, "%d %d\n", 1, 2); printf("%lld ns\n", times); auto times2 = runAndReturnElapsedTime2(printf, "%d %d\n", 1, 2); printf("%lld ns\n", times2); }
템플릿 파라미터는 정수형 타입 값, 열거형 타입 값, 포인터 값, 참조형 변수등이 올 수 있으며, 이를 non-type 템플릿 파라미터라고 한다. (non-type 템플릿 파라미터는 디폴트 값을 줄 수 있음.)
템플릿 파라미터에 다른 템플릿이 올 수 있는데 이를 템플릿 템플릿 파라미터라 한다.
#include<iostream> #include<vector> using namespace std; //템플릿 파라미터에 다른 템플릿이 들어가있는 모습. template< typename T, template<typename E, typename Allocator = allocator<E>> class Container > class Grid { size_t mWidth; size_t mHeight; Container<T>* mCells; public: Grid<T, Container>(size_t inWidth, size_t inHeight) : mWidth(inWidth), mHeight(inHeight) { mCells = new Container<T>[mWidth]; for (size_t i = 0; i < mWidth; ++i) mCells[i].resize(mHeight); } ~Grid() { delete[] mCells; } }; int main() { Grid<int, vector> vGrid(5, 5); }
또한, using을 이용해서 별칭 템플릿을 만들 수 있다.
typedef를 사용한다면 타입이 결정된 템플릿 인스턴스에 대해서만 별칭을 만들 수 있고 템플릿 자체에 대한 별칭을 만들 수 없다.
template<typename T> using MyAllocList = std::list<T, MyAlloc<T>>; MyAllocList<Widget> lw; //std::list<Widget, MyAlloc<Widget>>과 같음 typdef std::list<T, MyAlloc<T>> MyAllocList2; //컴파일 에러: T가 결정되어야 함
'Programming > _C++' 카테고리의 다른 글
_C++_연관 컨테이너_비순차 연관 컨테이너 (1) 2023.09.25 _C++_알고리즘_Part_2 (1) 2023.09.25 _C++_컨테이너 어댑터와 비트셋 컨테이너 (0) 2023.09.20 _C++_lambda (0) 2023.09.20 _C++_Scope (0) 2023.09.20