코딩/C++

[c++] template 사용하기

peter_00 2024. 8. 22. 16:41
반응형
#include <iostream>
using namespace std;

template <typename T>
T reverse (T x)
{
  return (-x);
}

int main() {
  int a = 10;
  float b = 15.4;

  cout<<reverse(a)<<endl;
  cout<<reverse(b)<<endl;

  return (0);
}

위 코드는 템플릿을 사용하는 예시이다

main 코드에 있는 reverse(a) 에서 a는 int 로 분류가 된다 왜냐하면 int a = 10; 이라고 값을 지정 했기 때문이다.

reverse(b)는 float 이다

template<typename T>
T findLargest( T x, T y, T z ) {
	T largest;
	largest = (x < y)? y : x;
	largest = (largest < z)? z: largest;

	return largest;
}

largest = (x < y) ? y : x; 이 부분을 설명하기 위해서 조건을 이해 해야한다.

 

( E1 ) ? E2 : E3;   

if E1의 조건을 만족하면 E2 값을 내보내고 그렇지 않다면 E3 값을 내보낸다

 

에를 들어 x 는 5 y 는 10 z 는 15 라고 가정해보자

largest = (5 < 10) ?  먼저 살펴보면 5 는 10 보다 작다 그러니 true 값을 내보낸다 조건이 true 이므로

largest 는 y :x ( 10 : 5 )  즉 10 을 값으로 내보낸다

그 다음 largest를 살펴보면 (10 < z ) ? z : 10 이 되는데 (10 < 15 ) 이므로 true 이다

그러므로 z 인 15 를 largest 로 내보낸다.

int main() {
    int a = 5, b = 10, c = 3;
    int largestInt = findLargest(a, b, c);
    
    double d = 2.3, e = 3.6, f = 1.2;
    double largestDouble = findLargest(d, e, f);

    // Outputs: 10 and 3.6
    std::cout << "Largest int: " << largestInt << std::endl;
    std::cout << "Largest double: " << largestDouble << std::endl;
    
    return 0;
}

이런식으로 main 코드를 짜고 template 을 설정 해주면 findLargest 만 불러와서 3 개의 수의 최대값을 쉽게 나타낼 수 있다

 

operator 에 관하여

#include <iostream>
using namespace std;

class PhoneCall {
    friend ostream& operator<<(ostream&, const PhoneCall&); // Declare friend function

private:
    int minutes; // Private data member

public:
    PhoneCall(int m = 0) : minutes(m) {} // Constructor with default value

    // Overloading < operator for comparison, but not relevant to operator<< explanation
    bool operator<(const PhoneCall& p) {
        return minutes < p.minutes;
    }
};

// Definition of the overloaded << operator
ostream& operator<<(ostream& out, const PhoneCall& p) {
    out << "Phone call lasted " << p.minutes << " minutes";
    return out; // Return ostream to allow chaining
}

int main() {
    PhoneCall call(10);

    // Using the overloaded << operator to print the PhoneCall object
    cout << call << endl;  // Outputs: Phone call lasted 10 minutes

    return 0;
}

operator 는 주로
(반환형 return_type) operator(연산자 symbol) (연산을 할 대상 parameters) 

반환형 return_type 은 오퍼레이터가 불러와야하는 값

operator 는 연산자의 타입에 따라 오버로딩

연산을 할 대상  parameters 는 오퍼레이터가 연산을 해야하는 대상이다

그렇다면 위 코드를 참조하면

bool (반환형) operator < (연산자 symbol) (const PhoneCall& p) (연산을 할 대상 parameters) 가 된다

(const PhoneCall& p) (const ClassName& other) 형식이라고 생각하면 된다

template<typename T>
void repeatValue( T val, int  num ) {
    for( int i=0; i<num; i++ )
        cout << val << " ";
    cout << endl;
}

 

 

T val 을 참고해서 val을 코드 내에서 찾는다

템플릿 안에 있는 모든 데이터 타입에 오퍼레이터인 << 가 부여되어야 한다

 

class Store {
    friend ostream& operator<<(ostream&, const Store&);
    private:
        int id;
        string address;
        string manager;
    public:
        Store(int =0, string ="", string ="");
};

Store::Store(int n, string addr, string m) {
    id = n;
    address = addr; 
    manager = m;
}

ostream& operator<<(ostream &out, const Store &s) {
    out << "Number: " << s.id << endl;
    out << "Address: " << s.address << endl;
    out << "Manager: " << s.manager << endl;
    
    return out;
}

출력 오퍼레이터 Stream operators ('<<' , '>>') 예시

friend std::ostream& operator<<(std::ostream& out, const ClassName& obj); // Example: Stream insertion

 

insertion opreator 를 오버로드 했다 ostream& 은 왼쪽이되고 const store&는 오른쪽이된다.

private 은 attribute들 이고

public 은 기본 constructor 이다

constructor 인 public 안에 있는 store의 값을 부여하는 코드인 implementation 코드가 있다

 

overloaded 된 instertion operator 인 ostream & operator<< 이다

opertor<< 는 friend 로 overloaded 되어야 한다.

friend 는 private에 엑세스 할수있기 때문에

s.id s.address 그리고 s.manager가 가능해진다

template<typename T>
void repeatValue( T val, int  num ) {
    for( int i=0; i<num; i++ )
        cout << val << " ";
    cout << endl;
}
int main() {
    int a = 12;
    float b = 12.5;
    double c = 23.882;
    Store s(1, "1 Northfield Ave", "Alice");
    
    repeatValue( a, 3 );
    repeatValue( b, 5 );
    repeatValue( c, 7 );
    repeatValue( s, 2 );
}

a 는 템플릿을 참고해서 T val 이기 때문에 a 는 val이 된다

하지만 main 코드에서 int a = 12 라고 값을 지정했으므로

a 는 3 과 같이 int 가 된다.

b는 float

c는 double

마지막 s 는 Store 이다.

 

2개의 템플릿을 사용하는 경우

template< typename T, typename U >
void displayAndCompare(T val1, U val2) {
    cout << "val1=" << val1 << ", val2=" << val2 << endl;
    if(val1 < val2) 
        cout << "The second one is larger." << endl;
    else if(val1 == val2)
        cout << "They are the same." << endl;
    else
        cout << "The first one is larger." << endl;
}

3 개의 오퍼레이터가 있다 

<< , < , == 

 

class PhoneCall {
    friend ostream& operator<<(ostream&, const PhoneCall&);
    private:
        int minutes;
    public:
        PhoneCall(int = 0);
        bool operator<( const PhoneCall & );  // PhoneCall < PhoneCall
        bool operator<( int n );              // PhoneCall < int
        bool operator==( const PhoneCall & ); // PhoneCall == PhoneCall
        bool operator==( int n );             // PhoneCall == int
};

위 코드에는 operator 가 5개 있다 

제일 처음 friend ostream& operator<<(ostream&, const PhoneCall&); 에서의 "operator<<"

bool operator<( const PhoneCall & ); 에서의 "operator<"

bool operator<( inst n ); 같은 operator< 이지만 각각 다른 type 이기 때문에 다른 operator 로 분류된다

bool operator==( const PhoneCall & ); 에서의 "operator=="

bool operator==( int n ); 같은 operator== 이지만 다른 type

ostream& operator<<( ostream& ost, const PhoneCall& p ) {
    ost << p.minutes;
    return ost;
}

PhoneCall::PhoneCall(int value) : minutes(value){}

bool PhoneCall::operator<( const PhoneCall& p ) {
    return ( (minutes < p.minutes)? true: false ); }

bool PhoneCall::operator<( int m ) {
    return ( (minutes < m)? true: false ); }

bool PhoneCall::operator==( const PhoneCall& p ) {
    return ( (minutes == p.minutes) ? true: false ); }

bool PhoneCall::operator==( int m ) {
    return ( (minutes == m)? true: false ); }

member function 은 classname :: operator 이 붙는 코드들이다

ostream& operator<< 코드는

PhoneCall& p 를 참조해서 private attirbute 인 p.minutes 으로 보내고 ost를 이용해 결과값으로 내보낸다

mintues 의 값이 불러오는 값인 int, const들 보다 큰지에 대해 비교하는 템플릿들이다

 

int main() {
    double a = 3.8, b=4.5, c=6.825;
    float x = 3.1415;
    displayAndCompare( a, b );    
    displayAndCompare( a, x ); 
    
    PhoneCall call1( 5 );
    PhoneCall call2( 8 );
    
    displayAndCompare( call1, call2 );
    displayAndCompare( call1, 5 ); 
}

displayAndCompare( a, b );

  • T 는 double
  • U 는 double
  • double a = 3.8, b=4.5, c=6.825; 이여서 a 와 b 가 double 이여서 T 와 U 도 double 이다

displayAndCompare( a, x );

  • T 는 double
  • U 는 float
  • float x = 3.1415; 이기 때문에 x 만 float 

displayAndCompare( call1, call2 );

  • T 는 PhoneCall 
  • U 는 PhoneCall
  • PhoneCall call1( 5 );
  • PhoneCall call2( 8 ); 이기 때문에 둘 다 PhoneCall임

displayAndCompare( call1, 5 );

  • T 는 PhoneCall
  • U 는 int 

오버로딩을 하는 템플릿의 타입을 정하고 싶다면

someFunction<char>(someArgument);

 

usigned 템플릿 typename T 가 없는 템플릿

template<unsigned N, unsigned M>
int compare(const char (&p1)[N], const char (&p2)[M])
{
	return strcmp(p1, p2);
}
compare("hi", "mum");                  produces
int compare(const char (&p1)[3], const char (&p2)[4])

 

compare ("hi", "mum"); 코드를 살펴보면 p1 은 hi 가 되고 p2 는 mum 이 된다 

hi 는 p1이 되고 [N] 은 3을 나타낸다

mum 은 p2가 되고 [M] 은 4를 나타낸다

 

0 1 2      0 1 2 3

h i \n      m u m \n   이런식으로 사이즈는 3 과 4 가 된다

 

템플릿 매개변수가 2개 이상일때

template<typename T1, typename T2>
class ClassName {
private:
    T1 attribute1;  // 첫 번째 템플릿 매개변수를 사용한 데이터 타입의 속성
    T2 attribute2;  // 두 번째 템플릿 매개변수를 사용한 데이터 타입의 속성

public:
    // 생성자: 두 개의 인자를 받아서 속성 초기화
    ClassName(const T1& a, const T2& b) : attribute1(a), attribute2(b) {}

    // 첫 번째 속성을 반환하는 멤버 함수
    T1 getAttribute1() const {
        return attribute1;
    }

    // 두 번째 속성을 반환하는 멤버 함수
    T2 getAttribute2() const {
        return attribute2;
    }
};

위 코드와 같이 typename 을 2 개 작성한다.

private 에는 각 typename 의 데이터가 어떠한 데이터를 의미하는지 지정해주면 된다.

const 를 붙이는 이유는 수정할 수 없는 값이라는 의미로 사용된다.

 

 

반응형