C++の方が便利です


私の観点では、覚えなければならないことだけを書くページに更新し続けます!

行内関数(行内)


マクロ関数の定義は複雑で、一般的な関数のように定義可能な方法を使用することができます.
方法は関数の前にinlineを追加することです.
マクロを使用する関数のインラインはフロントプロセッサで処理され、キーワードでインラインされた関数のインラインはコンパイラで処理されることに注意してください.
したがって、コンパイラが関数のインライン化がかえってパフォーマンスに有害であると判断した場合、このキーワードは無視されます.
さらに、コンパイラは、必要に応じていくつかの関数を任意にインライン処理することもできます.
ただし、マクロ関数はデータ型に依存しない関数であり、intでもdoubleでも入力すると自動的にデータが処理されますが、インライン関数であればデータ型は固定された関数なのでデータロスが発生します.
もちろん、関数のリロードは使用できますが、関数をもう1つ作成する必要があります.
ただし、C++にはテンプレートと呼ばれる最適な構文が存在するため、データ型に依存しない関数を作成することができます.

ネーミングスペース(namespace)


その名の通り、命名された空間です.
使用方法
namespace chanykim{
	void	func(void)
    {
    	std::cout << "함수명: chanykim"
    }
}

namespace chanyoung{
		void	func(void)
    {
    	std::cout << "함수명: chanyoung"
    }
}

int		main(void)
{
	chaykim::func();
    chayoung::func();
	return (0);
}
このように名前を付けると、同じ名前でも他の関数を作成して使用できます.
同じネーミングスペースで定義された関数を呼び出す場合は、ネーミングスペースを入れる必要はありません.
後で使用するネーミングスペースで明示することもできます.using namespace std;に指定すると、ネーミングスペースstdで宣言されたすべてのコンテンツコマンドに対してネーミングスペース指定を省略できます.

constの意味


constメンバー関数は、クラス内のメンバーが更新されないことを宣言する効果があります.
  • const int num = 10;
    ->定数化変数num
  • const int *ptr = &val;
    ->ポインタptrを使用してvalの値を変更できません
  • int * const ptr = &val;
    ->ポインタptrは通常量子化されています.
  • const int * const ptr = &val;
    ->ポインタptrは定数化されており、ptrを使用してvalの値を変更することはできません.
  • cont int *またはint const * は同じです.
    constはポインタを中心に左か右に変化します.
    constはポインタの右側で変数名を定数、左側で値を定数と見なします.
    ポインタがなければ、資料型に分けられるはずです.
    constオブジェクトはconstメンバー関数のみを呼び出すことができます.
    constメンバー関数と非constメンバー関数を繰り返すことができます.
    cont変数は初期化する必要があります.
    メンバー関数名にconstを付けると、そのメンバー関数内ですべてのメンバー変数が定数化されることを意味します.(領域変数は変更可能)

    参照者(&)


    参照者は、名前を付けたのと同じです.あだ名とか.つまり,自分が参照する変数のもう一つの名前に代わることができる.
    int num1 = 2021;
    int	*ptr = &num1; // 변수 num1의 주소 값을 반환해서 포인터 ptr에 저장하라.
    int &num2 = num1; // 변수 num1에 대한 참조자 num2를 선언해라.
    これにより、メモリに割り当てられた空間には2021の値があり、num 1とnum 2の2つの名前がある.num2 = 2022;に変更するとnum 1も2022に変更されます.
    あだ名に制限はありますか?いいえ.したがって、参照者の数を制限することなく、参照者に対して参照者を宣言することもできる.
    逆に、参照者(int&num)を直接宣言したり、NULL値(int&num=NULL)を参照したりすることはできず、変数のみを宣言し、定数として宣言することはできません.(int &num = 20)

    演算子のオーバーロード


    1.演算子+()関数

    #include <iostream>
    using namespace std;
    
    class Point{
    	int x;
    	int y;
    
    public:
    	Point(int _x=0, int _y=0):x(_x), y(_y){ }
    	void Print() const { cout << x << "," << y << endl; }
    	const Point operator+(const Point &value) const {
    		Point pv;
    		pv.x = this->x + value.x;
    		pv.y = this->y + value.y;
    		return pv;
    	}
    /* 위의 operator+ 함수를 간결하게 나타낸 코드
        const Point operator+(const Point &value) const {
    	return Point(x+value.x, y+value.y);
    	}
    */
    };
    
    int main() {
    	Point p1(3, 4), p2(5, 6);
    	Point p3;
    
    	p3 = p1 + p2; // p3=p1.operator+(p2)와 같다.
    	p3.Print();
    
    	p3 = p1.operator+(p2);
    	p3.Print();
    	return 0;
    }
    

    以上のコードで
    Point(int _x=0, int _y=0):x(_x), y(_y){ }
    このコードは、変数を作成しながら初期化するコードです.
    point( int _x=0, int _y=0 ){
        x=_x;
        y=_y;
    }
    上のコードと同じですが、最初に現れたコードのように書かなければなりません.作成と同時に初期化されるため、速度が速くなります.
    メンバー変数は、constや継承関係のサブクラスなどの初期化サブクラスで一般的に使用されます.

    2.+、--演算子の再ロード

    #include <iostream>
    using namespace std;
    
    class Point {
    	int x;
    	int y;
    
    public:
    	Point(int _x = 0, int _y = 0) :x(_x), y(_y) { }
    	void Print() const { cout << x << "," << y << endl; }
    	const Point operator ++(){ //전위 ++
    		++x;
    		++y;
    		return *this;
    	}
    
    	const Point operator ++(int) { // 후위 ++
    		Point pv(x,y);
    		++x;
    		++y;
    		return pv;
    	}
     
    /* 중복 코드를 피하기 위한 방법 중 하나
    	const Point operator ++(int) { // 후위 ++
    		Point pv = *this;
    		++*this;
    		return pv;
    	}
    */
        
    };
    
    int main() {
    	Point p1(3, 4), p2(5, 6);
    	Point p3;
    
    	p3 = ++p1; //p1.operator++(); 과 같다.
    	p1.Print();
    	p3.Print();
    
    	p3 = p2++; //p2.operator++(0);과 같다.
    	p2.Print();
    	p3.Print();
    	return 0;
    }

    p 1単位の電位++演算子では、演算後を値とし、増加した4,5を出力する.
    p 2単位の接尾辞++演算子では、演算前の値であるため、p 3では同様に5,6が出力される.
    中間に出現する6,7は前演算後の出力値を示すため,6,7を出力する.
    --演算子のリロードは、++演算子のリロードで++を--に置き換えることができます.
    #include <iostream>
    using namespace std;
    
    class Point {
    	int x;
    	int y;
    
    public:
    	Point(int _x = 0, int _y = 0) :x(_x), y(_y) { }
    	void Print() const { cout << x << "," << y << endl; }
    	const Point operator --() { //전위 --
    		--x;
    		--y;
    		return *this;
    	}
    
    	const Point operator --(int) { // 후위 --
    		Point pv(x, y);
    		--x;
    		--y;
    		return pv;
    	}
    	/*
    		const Point operator --(int) { // 후위 --
    			Point pv = *this;
    			--*this;
    			return pv;
    		}
    	*/
    };
    
    int main() {
    	Point p1(3, 4), p2(5, 6);
    	Point p3;
    
    	p3 = --p1; //p1.operator--(); 과 같다.
    	p1.Print();
    	p3.Print();
    
    	p3 = p2--; //p2.operator--(0);과 같다.
    	p2.Print();
    	p3.Print();
    
    	return 0;
    }

    3. ==, !=演算子のオーバーロード


    ==演算子は、比較演算でtrueまたはfalse結果を返すboolタイプです.
    反対!===演算子の否定なので、==演算子を少し変えるだけです.
    #include <iostream>
    using namespace std;
    
    class Point {
    	int x;
    	int y;
    
    public:
    	Point(int _x = 0, int _y = 0) :x(_x), y(_y) { }
    	void Print() const { cout << x << "," << y << endl; }
    	bool operator==(const Point &value) const {
    		return x == value.x && y == value.y ? true : false;
    	}
    	bool operator!=(const Point &value) const {
    		return !(*this == value);
    	}
    };
    
    int main() {
    	Point p1(3, 4), p2(5, 6), p3(3, 4);
    	
    	if (p1 == p2) { //p1.operator==(p2)와 같다.
    		cout << "p1 == p2" << endl;
    	}
    	if (p2 == p3) { //p2.operator==(p3)와 같다.
    		cout << "p2 == p3" << endl;
    	}
    	if (p1 == p3) { //p1.operator==(p3)와 같다.
    		cout << "p1 == p3" << endl;
    	}
    	if (p1 != p2) { //p1.operator!=(p2)와 같다.
    		cout << "p1 != p2" << endl;
    	}
    	if (p2 != p3) { //p2.operator!=(p3)와 같다.
    		cout << "p2 != p3" << endl;
    	}
    	if (p1 != p3) { //p1.operator!=(p3)와 같다.
    		cout << "p1 != p3" << endl;
    	}
    
    	return 0;
    }

    4.グローバル関数を使用した演算子のロード


    上の+演算子を使用して再ロードして作成します.
    #include <iostream>
    using namespace std;
    
    class Point {
    	int x;
    	int y;
    
    public:
    	Point(int _x = 0, int _y = 0) :x(_x), y(_y) { }
    	void Print() const { cout << x << "," << y << endl; }
    	int GetX() const { return x; } //x의 getter
    	int GetY() const { return y; } //y의 getter
    };
    
    const Point operator+ (const Point& valueL, const Point& valueR){
    	return Point(valueL.GetX() + valueR.GetX(), valueL.GetY() + valueR.GetY());
    }
    
    
    int main() {
    	Point p1(3, 4), p2(5, 6);
    	Point p3;
    
    	p3 = p1 + p2; 
    	p3.Print();
    
    	return 0;
    }

    グローバル関数を使用する場合、Pointクラスのプライベートメンバーx、yにアクセスできないため、getterまたはハイブリッド関数を使用できます.
    friend関数はprivateおよびprotectedメンバーにアクセスできます.
    #include <iostream>
    using namespace std;
    
    class Point {
    	int x;
    	int y;
    
    public:
    	Point(int _x = 0, int _y = 0) :x(_x), y(_y) { }
    	void Print() const { cout << x << "," << y << endl; }
    	friend const Point operator+ (const Point& valueL, const Point& valueR);
    };
    
    const Point operator+ (const Point& valueL, const Point& valueR){
    	return Point(valueL.x + valueR.x, valueL.y + valueR.y);
    }
    
    
    int main() {
    	Point p1(3, 4), p2(5, 6);
    	Point p3;
    
    	p3 = p1 + p2; 
    	p3.Print();
    
    	return 0;
    }

    5.関数呼び出し演算子のリロード(()演算子)


    オブジェクトを関数のように動かす演算子.
    #include <iostream>
    using namespace std;
    
    struct FuncObject {
    public:
    	void operator()(int value) const{
    		cout << "정수: " << value << endl;
    	}
    };
    
    void Print1(int value) {
    	cout << "정수: " << value << endl;
    }
    
    int main(){
    	void(*Print2)(int) = Print1;
    	FuncObject Print3;
    	Print1(10); // 함수를 사용한 정수 출력
    	Print2(10); // 함수 포인터를 사용한 정수 출력
    	Print3(10); // 함수 객체를 사용한 정수 출력
    	return 0;
    }
    いくつかの関数呼び出し演算子をロード
    #include <iostream>
    using namespace std;
    
    struct FuncObject {
    public:
    	void operator()(int value) const{
    		cout << "정수: " << value << endl;
    	}
    	void operator()(int value1, int value2) const {
    		cout << "정수: " << value1 <<',' << value2 << endl;
    	}
    	void operator()(int value1, int value2, int value3) const {
    		cout << "정수: " << value1 << ',' << value2 <<',' << value3 << endl;
    	}
    };
    
    
    int main(){
    	FuncObject Print;
    	Print(10); // 객체 생성 후 호출(암시적)
    	Print(10, 20);
    	Print(10, 20, 30);
    	cout << endl;
    
    	Print.operator()(10); // 객체 생성 후 호출(명시적)
    	Print.operator()(10, 20);
    	Print.operator()(10, 20, 30);
    	cout << endl;
    
    	FuncObject()(10); // 임시 객체로 호출(암시적)
    	FuncObject()(10, 20);
    	FuncObject()(10, 20, 30);
    	cout << endl;
    
    	FuncObject().operator()(10); // 임시 객체로 호출(명시적)
    	FuncObject().operator()(10, 20);
    	FuncObject().operator()(10, 20, 30);
    	cout << endl;
    
    	return 0;
    }

    6.配列インデックス演算子のロード([]演算子)


    ポイントの[]演算子の繰り返し
    #include <iostream>
    using namespace std;
    
    class Point {
    	int x;
    	int y;
    
    public:
    	Point(int _x = 0, int _y = 0) :x(_x), y(_y) { }
    	void Print() const { cout << x << "," << y << endl; }
    	
    	int operator[](int idx) const {
    		if (idx == 0) return x;
    		else if (idx == 1) return y;
    		else throw "안되잖아! 정지가 안돼!";
    	}
    };
    
    int main() {
    	Point pv(3, 4);
    	pv.Print();
    
    	cout << pv[0] << ',' // pv.operator[](0)호출
    		<< pv[1] << endl; //pv.operator[](1)호출
    	return 0;
    }
    整数を格納する単純なArrayクラス
    #include <iostream>
    using namespace std;
    
    class Array {
    	int *arr;
    	int size;
    	int capacity;
    
    public:
    	Array(int cap = 100) :arr(0), size(0), capacity(cap) {
    		arr = new int[capacity];
    	}
    	~Array() {
    		delete[] arr;
    	}
    
    	void Add(int data) {
    		if (size < capacity) arr[size++] = data;
    	}
    
    	int Size() const {
    		return size;
    	}
    
    	int operator[](int idx) const {
    		return arr[idx];
    	}
    };
    
    int main() {
    	Array ar(10);
    	
    	ar.Add(10);
    	ar.Add(20);
    	ar.Add(30);
    
    	for (int i = 0;i< ar.Size();i++) {
    		cout << ar[i] << endl; // ar.operator[](i) 와 같다.
    	}
    
    	return 0;
    }
    Ar[i]はar.オペレータarオブジェクトを返すi要素オブジェクトを呼び出します。 したがってarr[0]は10であり、arr[1]は20であり、arr[2]は30である。2

    상수 객체를 반환하는 []연산자 오버로딩

    #include <iostream>
    using namespace std;
    
    class Array {
    	int *arr;
    	int size;
    	int capacity;
    
    public:
    	Array(int cap = 100) :arr(0), size(0), capacity(cap) {
    		arr = new int[capacity];
    	}
    	~Array() {
    		delete[] arr;
    	}
    
    	void Add(int data) {
    		if (size < capacity) arr[size++] = data;
    	}
    
    	int Size() const {
    		return size;
    	}
    
    	int operator[](int idx) const {
    		return arr[idx];
    	}
    	int& operator[](int idx){
    		return arr[idx];
    	}
    };
    
    int main() {
    	Array ar(10);
    
    	ar.Add(10);
    	ar.Add(20);
    	ar.Add(30);
    
    	cout << ar[0] << endl;
    	cout << endl;
    
    	const Array& ar2 = ar;
    	cout << ar2[0] << endl;
    	cout << endl;
    
    	ar[0] = 100; //ar.operator[](int)를 호출
    	//ar2[0] = 100; error! 상수 객체(값)를 반환하므로 대입 불가
    	cout << ar[0] << endl;
    	return 0;
    }

    7.メモリアクセス、クラスメンバーアクセス演算子の再ロード(*.->演算子)

    point 클래스의 일반 포인터 사용

    #include <iostream>
    using namespace std;
    
    class Point {
    	int x;
    	int y;
    
    public:
    	Point(int _x = 0, int _y = 0) :x(_x), y(_y) { }
    	void Print() const { cout << x << "," << y << endl; }
    };
    
     
    int main() {
    	Point *p1 = new Point(2, 3);// 메모리 할당
    	Point *p2 = new Point(5, 6);// 메모리 할당
    
    	p1->Print(); // p1의 멤버 함수 호출
    	p2->Print(); // p2의 멤버 함수 호출
    
    	delete p1; //메모리 제거
    	delete p2; //메모리 제거
    
    	return 0;
    }

    스마트 포인터 PointPtr 클래스 생성

    #include <iostream>
    using namespace std;
    
    class Point {
    	int x;
    	int y;
    
    public:
    	Point(int _x = 0, int _y = 0) :x(_x), y(_y) { }
    	void Print() const { cout << x << "," << y << endl; }
    };
    
    class PointPtr {
    	Point *ptr;
    public:
    	PointPtr(Point *p):ptr(p){ }
    	~PointPtr() {
    		delete ptr;
    	}
    
    	Point * operator->() const {
    		return ptr;
    	}
    };
    
    int main() {
    	PointPtr p1 = new Point(2, 3);// 메모리 할당
    	PointPtr p2 = new Point(5, 6);// 메모리 할당
    
    	p1->Print(); // p1.operator->() ->Print() 호출
    	p2->Print(); // p2.operator->() ->Print() 호출
    
    	//p1,p2의 소멸자에서 Point 동적 객체를 자동으로 메모리에서 제거한다.
    
    	return 0;
    }

    *연산자 오버로딩

    #include <iostream>
    using namespace std;
    
    class Point {
    	int x;
    	int y;
    
    public:
    	Point(int _x = 0, int _y = 0) :x(_x), y(_y) { }
    	void Print() const { cout << x << "," << y << endl; }
    };
    
    class PointPtr {
    	Point *ptr;
    public:
    	PointPtr(Point *p) :ptr(p) { }
    	~PointPtr() {
    		delete ptr;
    	}
    
    	Point * operator->() const {
    		return ptr;
    	}
    	Point & operator*() const {
    		return *ptr;
    	}
    	
    };
    
    int main() {
    	Point* p1 = new Point(2, 3);// 메모리 할당
    	PointPtr p2 = new Point(5, 6);// 메모리 할당
    
    	p1->Print(); // p1->Print() 호출
    	p2->Print(); // p2.operator->() ->Print() 호출
    	cout << endl;
    
    	(*p1).Print(); //(*p1).Print()호출
    	(*p2).Print(); //p2.operator*().Print()호출
    
    	delete p1;
    	//p2의 소멸자에서 Point 동적 객체를 자동으로 메모리에서 제거한다.
    
    	return 0;
    }

    C++ Cast

    static cast

    static_cast<바꿀 자료형>(대상);
    기본 클래스에 대한 포인터를 파생 클래스에 대한 포인터로 변환하는 등의 작업에 사용할 수 있습니다.

    int i = 1;
    char c = i; //묵시적 캐스트
    char c = (char)i; //C언어에서의 명시적 캐스트
    char c = static_cast<char>(i); // c++ 명시적 캐스트

    const_cast

    const_cast<바꿀 자료형>(대상)
    포인터에 const 속성을 부여하거나 제거할 때 사용합니다.

    char arr[] = "Hello";
    const char* c = arr;
    char* cast = const_cast<char*>(c);

    reinterpret_cast

    reinterpret_cast<바꿀 자료형>(대상)
    임의의 포인터 타입끼리 변환을 허용하는 캐스트 연산자입니다.

    
    struct Data
    {
    	std::string	str;
    	int			value;
    };
    
    uintptr_t	serialize(Data* ptr)
    {
    	return	reinterpret_cast<uintptr_t>(ptr);
    }
    
    Data* deserialize(uintptr_t raw)
    {
    	return reinterpret_cast<Data *>(raw);
    }
    
    int		main(void)
    {
    	Data	ptr;
    	ptr.str = "serialization";
    	ptr.value = 1234;
    
    	uintptr_t raw = serialize(&ptr);
    	Data *deserial = deserialize(raw);
    }

    dynamic_cast

    dynamic_cast<바꿀 자료형>(대상)

    상속 계층 관계를 가로지르거나 다운캐스팅시 사용되는 캐스팅 연산자입니다. 기본 클래스 객체에 대한 포인터(*)나 레퍼런스(&)의 타입을 자식 클래스, 혹은 형제 클래스의 타입으로 변환 할 수 있습니다.

    void	identify(Base* p)
    {
    	if (dynamic_cast<A*>(p))
    		std::cout << "A Pointer identify." << std::endl;
    	else if (dynamic_cast<B*>(p))
    		std::cout << "B Pointer identify." << std::endl;
    	else if (dynamic_cast<C*>(p))
    		std::cout << "C Pointer identify." << std::endl;
    }
    
    void	identify(Base& p)
    {
    	try
    	{
    		(void)dynamic_cast<A&>(p);
    		std::cout << "A Reference identify." << std::endl;
    	}
    	catch(const std::exception& e){ }
    
    	try
    	{
    		(void)dynamic_cast<B&>(p);
    		std::cout << "B Reference identify." << std::endl;
    	}
    	catch(const std::exception& e){ }
    
    	try
    	{
    		(void)dynamic_cast<C&>(p);
    		std::cout << "C Reference identify." << std::endl;
    	}
    	catch(const std::exception& e){ }	
    }

    여기서 포인터로 받아왔을 때는 if문으로 나눌 수 있지만 참조자로 받아오면 try catch문으로 나눠야 합니다.

    Template

    一般テンプレートの例

    함수 템플릿: 여러 함수를 만들어내는 함수의 틀
    클래스 템플릿: 여러 클래스를 만들어내는 클래스의 틀

    정수, 실수, 문자열 출력 오버로딩 함수와 함수 템플릿 비교

    //정수, 실수, 문자열 출력 오버로딩 함수
    #include <iostream>
    using namespace std;
    
    void Print(int a, int b) {
    	cout << a << ", " << b << endl;
    }
    
    void Print(double a, double b) {
    	cout << a << ", " << b << endl;
    }
    void Print(const char *a, const char *b) {
    	cout << a << ", " << b << endl;
    }
    int main() {
    	Print(10, 20); // 정수 출력
    	Print(4.321, 11.234); // 실수 출력
    	Print("LOVE", "you"); // 문자열 출력
    	return 0;
    }
    //함수 템플릿
    #include <iostream>
    using namespace std;
    
    template<typename T>
    void Print(T a, T b) {
    	cout << a << ", " << b << endl;
    }
     
    int main() {
    	Print(10, 20); // 정수 출력
    	Print(4.321, 11.234); // 실수 출력
    	Print("LOVE", "you"); // 문자열 출력
    	return 0;
    }


    함수 템플릿 정의는 함수 앞에 template<typename T>라는 키워드를 붙인다.

    T는 템플릿 매개변수이며 클라이언트에서 결정한다.
    클라이언트가 직접 타입을 지정하고 명시적으로 함수를 호출할 수 있다.
    결과는 아래와 같다.
    함수 템플릿의 명시적 타입 지정 후 호출

    //함수 템플릿의 명시적 타입 지정 후 호출
    #include <iostream>
    using namespace std;
    
    template<typename T>
    void Print(T a, T b) {
    	cout << a << ", " << b << endl;
    }
    
    int main() {
    	Print<int>(10, 20); // 정수 출력
    	Print<double>(4.321, 11.234); // 실수 출력
    	Print<const char*>("LOVE", "you"); // 문자열 출력
    	return 0;
    }

    두 개의 매개변수를 갖는 함수 템플릿

    //두 개의 매개변수를 갖는 함수 템플릿
    #include <iostream>
    using namespace std;
    
    template <typename T1, typename T2>
    void Print(T1 a, T2 b) {
    	cout << a << ", " << b << endl;
    }
    
    int main() {
    	Print(10, 11.123); // 정수, 실수 출력
    	Print("Hello", 28); // 문자열, 정수 출력
    	Print("LOVE", 100); // 문자열, 정수 출력
    	return 0;
    }

    템플릿을 지정할 때 template<typename T>를 template<class T>로 사용할 수 있다.

    Swap()함수를 템플릿 버전으로 만들 수 있다.

    Swap()템플릿 함수

    //Swap()템플릿 함수
    #include <iostream>
    using namespace std;
    
    template <typename T>
    void Swap(T &a, T &b) {
    	T temp = a;
    	a = b;
    	b = temp;
    }
    int main() {
    	int n1 = 10, n2 = 20;
    	double d1 = 1.1, d2 = 2.2;
    
    	cout << n1 << ", " << n2 << endl;
    	Swap(n1, n2);
    	cout << n1 << ", " << n2 << endl;
    
    	cout << endl;
    
    	cout << d1 << ", " << d2 << endl;
    	Swap(d1, d2);
    	cout << d1 << ", " << d2 << endl;
    
    	return 0;
    }

    배열 출력 함수 템플릿

    //배열 출력 함수 템플릿
    #include <iostream>
    using namespace std;
    
    template<typename T, int size>
    void PrintArray(T* arr) {
    	for (int i = 0; i < size; i++){
    		cout << "[" << i << "]: " << arr[i] << endl;
    	}
    	cout << endl;
    }
    
    int main() {
    	int arr1[5] = {10, 20, 30, 40, 50};
    	PrintArray<int, 5>(arr1); //명시적 호출
    	
    	double arr2[3] = {10.1, 20.2, 30.3};
    	PrintArray<double, 3>(arr2); //명시적 호출
    
    	return 0;
    }

    함수 템플릿 Print()의 특수화 버전

    //Point 객체만의 함수 템플릿 특수화 지원
    #include <iostream>
    using namespace std;
    
    class Point {
    	int x;
    	int y;
    public:
    	explicit Point(int _x=0, int _y=0): x(_x), y(_y){ }
    	void Print() const { cout << x << "," << y << endl; }
    };
    
    //일반화 함수 템플릿
    template<typename T>
    void Print(T a) {
    	cout << a << endl;
    }
    
    //특수화 함수 템플릿
    template< >
    void Print(Point a) {
    	cout << "Print 특수화 버전: ";
    	a.Print();
    }
    
    int main() {
    	int n(10);
    	double d(2.5);
    	Point pt(2, 3);
    
    	Print(n); //Print<int>(n) 일반화 버전 호출
    	Print(d); //Print<double>(d) 일반화 버전 호출
    	Print(pt); //Print<Point>(pt) 특수화 버전 호출, 특수화 함수 템플릿을 안했다면 에러남
    
    	return 0;
    }

    클래스 템플릿 ObjectInfo를 특수화해 string 정보만 출력하는 template<>class ObjectInfo<string>클래스를 추가한다.

    일반화버전: template<typename T> class ObjectInfo
    특수화버전: template<> class ObjectInfo<string>
    //Objectinfo 특수화 버전
    #include <iostream>
    #include <string>
    using namespace std;
    
    template<typename T>
    class ObjectInfo {
    	T data;
    public:
    	ObjectInfo(const T& d) : data(d) { }
    
    	void Print() {
    		cout << "타입: " << typeid(data).name() << endl;
    		cout << "크기: " << sizeof(data) << endl;
    		cout << "값: " << data << endl;
    		cout << endl;
    	}
    };
    
    template< > //T를 string으로 특수화(클래스 템플릿 특수화)
    class ObjectInfo<string> {
    	string data;
    public:
    	ObjectInfo(const string& d) : data(d) { }
    
    	void Print() {
    		cout << "타입: " << "string" << endl;
    		cout << "문자열 길이: " << data.size() << endl;
    		cout << "값: " << data << endl;
    		cout << endl;
    	}
    };
    int main() {
    	ObjectInfo<int> d1(10);
    	d1.Print(); // 객체 정보 출력
    
    	ObjectInfo<double> d2(4.5);
    	d2.Print(); // 객체 정보 출력
    
    	ObjectInfo<string> d3("Love");
    	d3.Print(); // 객체 정보 출력
    
    	return 0;
    }

    STLのテンプレート例

    함수 템플릿 For_each, Print

    //함수 템플릿 For_each, Print
    #include <iostream>
    #include <string>
    using namespace std;
    
    template<typename IterT, typename Func>
    void For_each(IterT begin, IterT end, Func pf) {
    	while (begin != end) {
    		pf(*begin++);
    	}
    }
    
    template<typename T>
    void Print(T data) {
    	cout << data << " ";
    }
    
    int main() {
    	int arr[5] = { 10, 20, 30, 40 ,50 };
    	For_each(arr, arr + 5, Print<int>); // 정수 출력
    	cout << endl;
    
    	string sarr[3] = { "adc", "ADCDE", "Hello!" };
    	For_each(sarr, sarr + 3, Print<string>); // 문자열 출력
    
    	return 0;
    }

    함수 객체를 사용한 For_each()

    //함수 객체를 사용한 For_each()
    #include <iostream>
    #include <string>
    using namespace std;
    
    template<typename IterT, typename Func>
    void For_each(IterT begin, IterT end, Func pf) {
    	while (begin != end) {
    		pf(*begin++);
    	}
    }
    
    template<typename T>
    struct PrintFunctor {
    	string sep; //출력 구분자 정보
    	explicit PrintFunctor(const string& s=" "): sep(s){ }
    	void operator()(T data) const {
    		cout << data << sep;
    	}
    };
    
    int main() {
    	int arr[5] = { 10, 20, 30, 40 ,50 };
    	For_each(arr, arr + 5, PrintFunctor<int>()); 
    	cout << endl;
    
    	string sarr[3] = { "adc", "ADCDE", "Hello!" };
    	For_each(sarr, sarr + 3, PrintFunctor<string>("*\n")); 
    	cout << endl;
    	return 0;
    }


    정수는 디폴트 출력 구분자로 " "(공백 문자열)을 사용하며 문자열은 출력 구분자로 "*\n"을 사용한다.

    템플릿 Less, Greater

    //템플릿 Less, Greater
    #include <iostream>
    #include <functional> //STL less와 greater 헤더
    using namespace std;
    
    template<typename T>
    struct Less {
    	bool operator()(T a, T b) {
    		return a < b;
    	}
    };
    
    template<typename T>
    struct Greater {
    	bool operator()(T a, T b) {
    		return a > b;
    	}
    };
    
    
    int main() {
    
    	cout << Less<int>()(10, 20) << endl; //사용자 Less, Greater 사용
    	cout << Less<int>()(20, 10) << endl; 
    	cout << Greater<int>()(10, 20) << endl;
    	cout << Greater<int>()(20, 10) << endl;
    	cout << endl;
    
    	cout << less<int>()(10, 20) << endl; //STL의 less, greater 사용
    	cout << less<int>()(20, 10) << endl;
    	cout << greater<int>()(10, 20) << endl;
    	cout << greater<int>()(20, 10) << endl;
    	return 0;
    }

    pair 클래스

    //pair 클래스
    #include <iostream>
    #include <string>
    using namespace std;
    
    template<typename T1, typename T2>
    struct UserPair {
    	T1 first;
    	T2 second;
    	UserPair(const T1& ft, const T2& sd): first(ft), second(sd){ }
    };
    
    int main() {
    	UserPair<int, int> p1(10, 20);
    	cout << p1.first << ", " << p1.second << endl;
    	
    	UserPair<int, string> p2(10, "Love");
    	cout << p1.first << ", " << p2.second << endl;
    
    	pair<int, int> p3(10, 20); // STL의 pair
    	cout << p3.first << ", " << p3.second << endl;
    
    	pair<double, string> p4(11.234, "you"); // STL의 pair
    	cout << p4.first << ", " << p4.second << endl;
    
    
    	return 0;
    }