튀김족발
공부 끄적이는 공간
튀김족발
전체 방문자
오늘
어제
  • 분류 전체보기 (33)
    • C++ (10)
    • DirectX (12)
    • Unreal (11)
    • Unity (0)
    • EASTL (0)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
튀김족발

공부 끄적이는 공간

C++

7. CRTP, Static Plymophism and Rebind

2023. 1. 9. 21:54

후... 연말, 연초에는 안바쁠거라고 하던 회사는 거짓말쟁이다. 야근밖에 안했다.. ㅠㅠ

 

CRTP(Curiously Recurring Template Pattern)

- 기반 클래스에서 파생 클래스의 이름을 사용할 수 있게 하는 기법

- 파생 클래스를 만들 때 기반 클래스의 템플릿 인자로 파생 클래스 이름을 전달.

 

이름부터 이상한 반복 템플릿 패턴이다. 어떻게 사용되는지 3개의 예시로 보자

 

Counter

template<typename T>
struct counter
{
	static int objects_created;
	static int objects_alive;

	counter()
	{
		++objects_created;
		++objects_alive;
	}

protected:
	~counter()
	{
		--objects_alive;
	}
};

template <typename T> int counter<T>::objects_created(0);
template <typename T> int counter<T>::objects_alive(0);

class X : counter<X>
{

};
// 이렇게 만들면 X에 관한 objects_ 변수들을 접근할 수 있게 된다.

class Y : counter<Y>
{

};

int main()
{
	return 0;
}

크게 counter 클래스에 static으로 create, alive 변수를 만들어준다. 그리고 X, Y 클래스 각각 counter의 템플릿 변수로 만들어주면 X를 만들때마다 X의 create, alive의 값이 올라가고 소멸할때 마다 alive의 값이 내려가 이 클래스를 만든 갯수를 파악할 수 있게 된다.

 

Static Ploymophisom

// StaticPolymophism을 사용하면 가상 함수(Virtual Function)을 구현 가능

template <class Derived>
struct Base
{
	void interface()
	{
		static_cast<Derived*>(this)->implementation();
	}

	static void static_func()
	{
		Derived::static_sub_func();
	}
};

struct Derived : Base<Derived>
{
	void implementation();
	static void static_sub_func();
};

int main()
{
	return 0;
}

이 방법은 가상함수를 만들지 않아도 가상함수처럼 작동하는 함수를 만들 수 있다.

interface를 먼저 호출하게 되는데 그렇게 되면 template 변수인 Derived의 implementation을 호출하게 된다.

static 멤버 함수도 마찬가지다.

Rebind

std::vector<int> a;
각 노드는 integer크기 만큼의 메모리를 사용하게 된다.

std::set<int> b;

set 은 RB 트리이기 때문에 integer와 양쪽 노드의 크기만큼의 메모리를 사용하게 된다.

그렇게 되면 set<int>의 allocator는 int가 아닌 int와 양쪽 노드를 모두 allocation을 해야 한다.
이를 위해 Rebind를 사용하게 된다.

// Custom Allocator가 유저가 정의한 타입이 아닌 타입의 추가한 정보를 allocation을 해야 할 때가 있음.
// set<int> 처럼 RB Tree를 사용할때 int가 아닌 left right 포인터를 allocation을 해야 함.

#include <iostream>
#include <iterator>

template<typename T>
class KType
{
public: 
	template <typename U>
	struct rebind
	{
		typedef KType<U> other;		// 자기 자신을 참조 이렇게 되면 U에 대해서 같은 KType을 접근 가능해짐
	};

	KType(){}
	KType(const KType&){}
	template <typename U>
	KType(const KType<U>&){}

	int size() { return sizeof(T); }
};

template<typename T, typename TALLOC=KType<T>> // TALLOC은 T를 allocation을 하고있기 때문에 나머지 값(next)을 모름
class KTest
{
public:
	typedef T value_type;
	struct _Node
	{
		value_type _data1;
		value_type _data2;
		_Node* _next;
	};

	KTest(){}
	void PrintNodeSize()
	{
		TALLOC a;
		TALLOC::template rebind<_Node>::template other allocator(a);			// 이렇게 하면 T를 allocation을 하는게 아닌 _Node를 allocation을 하게됨
		std::cout << allocator.size() << std::endl;
	}
};

int main()
{
	KTest<int> t;
	t.PrintNodeSize();
	return 0;
}

결과

12

총 12(int의 크기, pointer의 크기 * 2)를 출력한다.

'C++' 카테고리의 다른 글

9. STL Equality and Equivalence  (0) 2023.02.08
8. STL Custom Allocator  (0) 2023.02.07
6. STL Placement new  (0) 2022.12.17
5. Operator Overloading03 operator new  (2) 2022.12.17
4. Operator Overloading Ostream  (0) 2022.12.14
    'C++' 카테고리의 다른 글
    • 9. STL Equality and Equivalence
    • 8. STL Custom Allocator
    • 6. STL Placement new
    • 5. Operator Overloading03 operator new
    튀김족발
    튀김족발

    티스토리툴바