ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • _C++_Template
    Programming/_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  (0) 2023.09.25
    _C++_컨테이너 어댑터와 비트셋 컨테이너  (0) 2023.09.20
    _C++_lambda  (0) 2023.09.20
    _C++_Scope  (0) 2023.09.20
Designed by Tistory.