[따배C++] 13. 템플릿

Created: June 6, 2021 11:26 AM
Tag: specialization, template, templatize

13.1 템플릿


템플릿을 통해 반복되는 코드의 작성을 피할 수 있다. 다음은 자료형 외에 동일한 코드를 반복해서 사용하고자 하는 경우에 대해 예시이다.

#include <iostream>

template<typename T> // 변수명을 짓듯
T getMax(T x, T y)
{
	return ((x > y) ? x : y);
}

int main(void)
{
	std::cout << getMax(1, 2) << std::endl;
	std::cout << getMax(3.14, 1.592) << std::endl;
	std::cout << getMax(1.0f, 3.4f) << std::endl;
	std::cout << getMax('a', 'c') << std::endl;

	return (0);
}

// result
// 2
// 3.14
// 3.4
// c

13.2 클래스 템플릿 templatize


// main.cpp
#include "MyArray.h"

int main(void)
{
	MyArray<double> my_array(10);

	for (int i = 0; i < my_array.getLength(); ++i)
		my_array[i] = i * 0.5;

	my_array.print();

	return (0);
}

// ==============================
// MyArray.h
#include <assert.h> // for assert()
#include <iostream>

template<typename T>
class MyArray
{
private:
	int m_length;
	T *m_data; // <-

public:
	MyArray()
	{
		m_length = 0;
		m_data = nullptr;
	}

	MyArray(int length)
	{
		m_data = new T [length];
		m_length = length;
	}

	~MyArray()
	{
		reset();
	}

	void reset()
	{
		delete[] m_data;
		m_data = nullptr;
		m_length = 0;
	}

	T &operator[](int index)
	{
		assert(index >= 0 && index < m_length);
		return (m_data[index]);
	}

	int getLength()
	{
		return (m_length);
	}

	void print()
	{
		for (int i = 0; i < m_length; ++i)
			std::cout << m_data[i] << " ";
		std::cout << std::endl;
	}
};

13.3 자료형이 아닌 템플릿 매개변수 non type parameters


자료형이 아닌 객체에 대한 템플릿화에 대해 알아보자. 한편 템플릿 기능은 코드에 따라 컴파일을 다르게 해주는 개념으로 이에따라 일부 객체들은 반드시 컴파일 전에 값이 결정되어 있어야 한다.

// main.cpp
#include "MyArray.h"

int main(void)
{
	MyArray<double, 100> my_array;

	for (int i = 0; i < my_array.getLength(); ++i)
		my_array[i] = i + 65;

	my_array.print();

	return (0);
}

// ==============================
// MyArray.h
#include <assert.h>
#include <iostream>

template<typename T, unsigned int T_SIZE>
class MyArray
{
private:
	T	*m_data; // T m_data[T_SIZE]

public:
	MyArray()
	{
		m_data = new T [T_SIZE];
	}

	// ...

	int getLength()
	{
		return (T_SIZE);
	}

	void print()
	{
		for (int i = 0; i < T_SIZE; ++i)
			std::cout << m_data[i] << " ";
		std::cout << std::endl;
	}
};

13.4 함수 템플릿 특수화 specialization


특정 타입에 대해 함수를 특수화 하고자 한다면 다음의 함수 템플릿 특수화를 활용할 수 있다.

#include <iostream>

using namespace std;

template<typename T>
T getMax(T x, T y)
{
	return ((x > y) ? x : y);
}

template<>
// char type에 대해 instanciation이 되는 경우에는 다음의 코드를 사용!
char getMax(char x, char y)
{
	cout << "Warning : Comparing chars" << endl;

	return ((x > y) ? x : y);
}

int main(void)
{
	cout << getMax(1, 2) << endl;
	cout << getMax<double>(1, 2) << endl; // 강제로 double로 빌드
	cout << getMax('a', 'b') << endl; // Warning

	return (0);
}

13.5 클래스 템플릿 특수화 specialization


#include <iostream>
#include <array>

using namespace std;

template<typename T>
class A
{
public:
	A(const T& input)
	{}

	void doSomething()
	{
		cout << typeid(T).name() << endl;
	}

	void test()
	{}
};

template<>
class A<char>
{
public:
	A(const char & temp);

	void doSomething()
	{
		cout << "Char type specialization" << endl;
	}
};

int main(void)
{
	A<int>		a_int(1);
	A<double>	a_double(3.14);
	A<char>		a_char('a');

	a_int.doSomething();
	a_double.doSomething();
	a_char.doSomething();
}

13.6 템플릿을 부분적으로 특수화하기 partial specialization


#include <iostream>
#include <string.h>
using namespace std;

template <class T, int size>
class StaticArray
{
private:
	T m_array[size];

public:
	T * getArray() { return (m_array); }

	T &operator[](int index)
	{
		return (m_array[index]);
	}
};

template <typename T, int size>
void print(StaticArray<T, size> &array)
{
	for (int count = 0; count < size; ++count)
		std::cout << array[count] << ' '; // <- 부분적으로 나누어 특수화!
	std::cout << endl;
}

template <int size>
void print(StaticArray<char, size> &array)
{
	for (int count = 0; count < size; ++count)
		std::cout << array[count]; // <- 숫자는 한칸씩 띄어지지만 글자는 붙은 형태로 출력!
	std::cout << endl;
}

int main(void)
{
	StaticArray<int, 4> int4;
	int4[0] = 1;
	int4[1] = 2;
	int4[2] = 3;
	int4[3] = 4;

	print(int4);

	StaticArray<char, 14> char14;
	char14[0] = 'H';
	char14[1] = 'e';
	// ...
	strcpy_s(char14.getArray(), 14, "Hello, World");

	print(char14);
}

13.7 포인터에 대한 템플릿 특수화


#include <iostream>
using namespace std;

template<class T>
class A
{
private:
	T m_value;

public:
	A(const T &input)
		: m_value(input)
	{

	}

	void print()
	{
		cout << m_value << endl;
	}
};

template<class T>
class A<T*>
{
private:
	T* m_value;

public:
	A(T *input)
		: m_value(input)
	{

	}

	void print()
	{
		cout << *m_value << endl;
	}
};

int main(void)
{
	A<int> a_int(123);
	a_int.print();

	int temp = 456;

	A<int *> a_int_ptr(&temp);
	a_int_ptr.print();

	double temp_d = 3.141592;
	A<double *> a_double_ptr(&temp_d);
	a_double_ptr.print();

	return (0);
}

13.8 맴버 함수를 한번 더 템플릿화 하기 templatize


#include <iostream>
using namespace std;

template<class T>
class A
{
private:
	T m_value;

public:
	A(const T &input)
		: m_value(input)
	{

	}

	template<typename TT>
	void doSomething(const TT &input)
	{
		cout << typeid(T).name() << " " << typeid(TT).name() << endl;
	}

	void print()
	{
		cout << m_value << endl;
	}
};

int main(void)
{
	A<int> a_int(123);

	a_int.doSomething<float>(123.4);
	a_int.doSomething('a');

	return (0);
}

좋은 웹페이지 즐겨찾기