[C++] 함수 템플릿과 클래스 템플릿

2024. 6. 28. 19:41·Programming Language(Sub)/C++

함수 템플릿과 클래스 템플릿

함수 템플릿

  • 배열의 합을 구하는 예제를 봐보자
#include <iostream>
using namespace std;

int getArraySum(const int arr[], int n) {
    int sum = 0;
    for (int i = 0; i < n; i++) {
        sum += arr[i];
    }
    return sum;
}

int main() {
    int arr[5] = { 3, 1, 4, 1, 5 };
    int sum = getArraySum(arr, 5);
    cout << sum << endl;
}
  • int 형이 아닌 float 타입등 여러 자료형으로 이루어진 배열의 합을 구하고 싶은 경우가 있을 것이다.

    • 이 때 Overloading을 통해서 float getArraySum이라는 함수를 또 만들어 줘야 한다
#include <iostream>
using namespace std;

int getArraySum(const int arr[], int n) {
    int sum = 0;
    for (int i = 0; i < n; i++) {
        sum += arr[i];
    }
    return sum;
}

float getArraySum(const float arr[], int n) {
    float sum = 0;
    for (int i = 0; i < n; i++) {
        sum += arr[i];
    }
    return sum;
}

int main() {
    int arr[5] = { 3, 1, 4, 1, 5 };
    float farr[5] = { 3.1, 1.2, 4.3, 1.4, 5.5 };
    float sum = getArraySum(farr, 5);
    cout << sum << endl;
}
  • float 자료형 이외에도 다른 자료형의 합을 구할 경우가 생길 수 있는데, 이 때 자료형 부분만 다르고 나머지는 공통적이므로, 자료형을 T라고 치환해서 처리하면 깔끔할 것 같다
T getArraySum(const T arr[], int n) {
    T sum = 0;
    for (int i = 0; i < n; i++) {
        sum += arr[i];
    }
    return sum;
}
  • 위와 같은 기능을 해주는 것이 함수 템플릿이다.
#include <iostream>
using namespace std;

template<typename T>
T getArraySum(const T arr[], int n) {
    T sum = 0;
    for (int i = 0; i < n; i++) {
        sum += arr[i];
    }
    return sum;
}

int main() {
    int iarr[5] = {3, 1, 4, 1, 5};
    float farr[5] = {3.1, 1.2, 4.3, 1.4, 5.5};
    int isum = getArraySum<int>(iarr, 5);
    float fsum = getArraySum<float>(farr, 5);
    cout << isum << endl;
    cout << fsum << endl;
}
  • 임의의 타입에 대한 함수를 찍어낼 수 있다.

  • typename T : 타입 파라미터

  • getArraySum : int 버전의 getArraySum을 만들어라

  • 템플릿은 템플릿 자체로 함수가 아니다. 함수를 생성해주는 템플릿이다.

  • 템플릿 하나만 만들어 준다면 임의의 타입에 대해서도 함수를 생성해준다

Example) Vector 클래스

#include <iostream>
using namespace std;

class Vector2 {
   public:
    Vector2() : x(0), y(0) {}
    Vector2(float x, float y) : x(x), y(y) {}
    float GetX() const { return x; }
    float GetY() const { return y; }

   private:
    float x, y;
};

template <typename T>
T getArraySum(const T arr[], int n) {
    T sum = 0;
    for (int i = 0; i < n; i++) {
        sum += arr[i];
    }
    return sum;
}

int main() {
    int iarr[5] = {3, 1, 4, 1, 5};
    float farr[5] = {3.1, 1.2, 4.3, 1.4, 5.5};
    Vector2 varr[3] = { Vector2(1, 2), Vector2(3,4), Vector2(5, 6) };

    int isum = getArraySum<int>(iarr, 5);
    float fsum = getArraySum<float>(farr, 5);
    Vector2 vsum = getArraySum<Vector2>(varr, 5);

    cout << isum << endl;
    cout << fsum << endl;
}
  • 컴파일 타임에 에러가 발생한다

    • 함수를 만들려고 할 때 T sum = 0에서 0을 Vector2 타입으로 변환하는 과정에서 오류가 발생한다
  • 해결책 1

    • T sum = arr[0];으로 하고 for문을 i = 1 부터 돌려보자
template <typename T>
T getArraySum(const T arr[], int n) {
    T sum = arr[0];
    for (int i = 1; i < n; i++) {
        sum += arr[i];
    }
    return sum;
}
  • 이렇게 해도 오류가 발생한다

    • Vector2 클래스의 += 연산자에 대한 정의가 되어있지 않아 오류가 발생한다.

    • 연산자 오버로딩을 해줘야 한다

class Vector2 {
   public:
    Vector2() : x(0), y(0) {}
    Vector2(float x, float y) : x(x), y(y) {}
    float GetX() const { return x; }
    float GetY() const { return y; }

    Vector2 &operator+=(const Vector2 &rhs) {
        x += rhs.x;
        y += rhs.y;
        return *this;
    }

   private:
    float x, y;
};

int main() {
    int iarr[5] = {3, 1, 4, 1, 5};
    float farr[5] = {3.1, 1.2, 4.3, 1.4, 5.5};
    Vector2 varr[3] = { Vector2(1, 2), Vector2(3,4), Vector2(5, 6) };

    int isum = getArraySum<int>(iarr, 5);
        // getArraySum(iarr, 5); 도 가능하다
    float fsum = getArraySum<float>(farr, 5);
        // getArraySum(farr, 5); 도 가능하다
    Vector2 vsum = getArraySum<Vector2>(varr, 5);
        // getArraySum(varr, 5); 도 가능하다
    cout << isum << endl;
    cout << fsum << endl;
    cout << vsum.GetX() << ", " << vsum.GetY() << endl;
}
  • getArraySum(iarr, 5)에서 굳이 를 안밝혀주고 getArraySum(iarr, 5)로 적어도 컴파일러가 알아서 타입을 추정해준다

    • 즉, 타입 인수를 생략해도 된다
  • string 타입 배열에 대해서도 작동한다

int main() {
    int iarr[5] = {3, 1, 4, 1, 5};
    float farr[5] = {3.1, 1.2, 4.3, 1.4, 5.5};
    Vector2 varr[3] = { Vector2(1, 2), Vector2(3,4), Vector2(5, 6) };
    string sarr[3] = { "hello", "world", "luna" };

    int isum = getArraySum<int>(iarr, 5);
    float fsum = getArraySum<float>(farr, 5);
    Vector2 vsum = getArraySum<Vector2>(varr, 5);
    string ssum = getArraySum(sarr, 3);

    cout << isum << endl;
    cout << fsum << endl;
    cout << vsum.GetX() << ", " << vsum.GetY() << endl;
    cout << ssum << endl;
}
  • 위에서 T sum = arr[0]로 바꿨던 해결책 1 말고도 다른 방법이 존재한다. 아래 코드를 봐보자
template <typename T>
T getArraySum(const T arr[], int n) {
    T sum = new T();
        // T sum;은 불가능
    for (int i = 1; i < n; i++) {
        sum += arr[i];
    }
    return sum;
}
  • T의 기본 생성자를 호출한다.

    • int나 float의 경우 0으로 초기화되고, 사용자 정의 클래스에서는 각 클래스에서 정의한 기본 생성자가 호출된다

    • string의 경우 빈 문자열이 생긴다

  • T sum; 요거는 불가능 하다

클래스 템플릿

Example) Vector 클래스

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

class Vector2 {
   public:
    Vector2() : x(0), y(0) {}
    Vector2(float x, float y) : x(x), y(y) {}
    float GetX() const { return x; }
    float GetY() const { return y; }

    Vector2 operator+(const Vector2 &rhs) const {
        return Vector2(x + rhs.x, y + rhs.y);
    }

    Vector2 operator-(const Vector2 &rhs) const {
        return Vector2(x - rhs.x, y - rhs.y);
    }

    Vector2 &operator+=(const Vector2 &rhs) {
        x += rhs.x;
        y += rhs.y;
        return *this;
    }

    Vector2 &operator-=(const Vector2 &rhs) {
        x -= rhs.x;
        y -= rhs.y;
        return *this;
    }

   private:
    float x, y;
};

int main() {
    Vector2 v1(2, 3);
}
  • Vector2 클래스에서 float 말고도 int, double 등등의 타입을 담을 수 있게 만들고 싶다.

    • Vector2d, Vector2i와 같이 별도로 클래스를 만드는 것은 매우 번거로움
  • 클래스 템플릿이라는 것을 사용하면 쉽게 구현할 수 있다.

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

template <typename T>
class Vector2 {
   public:
    Vector2() : x(0), y(0) {}
    Vector2(T x, T y) : x(x), y(y) {}
    T GetX() const { return x; }
    T GetY() const { return y; }

    Vector2 operator+(const Vector2 &rhs) const {
        return Vector2(x + rhs.x, y + rhs.y);
    }

    Vector2 operator-(const Vector2 &rhs) const {
        return Vector2(x - rhs.x, y - rhs.y);
    }

    Vector2 &operator+=(const Vector2 &rhs) {
        x += rhs.x;
        y += rhs.y;
        return *this;
    }

    Vector2 &operator-=(const Vector2 &rhs) {
        x -= rhs.x;
        y -= rhs.y;
        return *this;
    }

   private:
    T x, y;
};

int main() {
    Vector2<float> v1(2, 3);
    Vector2<double> v2(4, 5);
}
  • Tip)

    • Mac의 경우 vscode에서 커맨드 + Shift + L을 통해서 한 번에 바꾸기를 할 수 있다.

      • 윈도우의 경우 아마 ctrl + h로 가능했던 것 같다.
  • Vector2와 Vector2은 다른 타입이다.

    • Vector2 자체는 클래스가 아니라 클래스를 만들어내는 템플릿이기 때문
  • Vector2는 8바이트 크기를 갖는다는 것을 알 수 있고, Vector2은 16바이트 크기를 갖는다는 것을 알 수 있다.

  • 주의! 클래스 템플릿에서는 템플릿 인수를 생략할 수 없다.

질문) Vector2는 클래스가 아니라 클래스 템플릿인데, 연산자 오버로딩에서 클래스를 어떻게 다루는거죠?

template <typename T>
class Vector2 {
   public:
    /* 생략 */
    Vector2 operator+(const Vector2 &rhs) const {
        return Vector2(x + rhs.x, y + rhs.y);
    }

    Vector2 operator-(const Vector2 &rhs) const {
        return Vector2(x - rhs.x, y - rhs.y);
    }

    Vector2 &operator+=(const Vector2 &rhs) {
        x += rhs.x;
        y += rhs.y;
        return *this;
    }

    Vector2 &operator-=(const Vector2 &rhs) {
        x -= rhs.x;
        y -= rhs.y;
        return *this;
    }

   private:
    T x, y;
};
  • 여기서 Vector2를 클래스 템플릿이 아니라 클래스인 것 마냥 사용하고 있다.

    • 이게 어떻게 가능하냐?

    • Vector2에서 가 생략되어 있는 것이다.

Vector2<T> operator+(const Vector2<T> &rhs) const {
        return Vector2(x + rhs.x, y + rhs.y);
}
  • 그리고 템플릿 인자를 2개 이상도 사용할 수 있다.
template <typename T, typename U>
void f(T a, U b) {}

참조) 두들낙서 C/C++ 강좌

'Programming Language(Sub) > C++' 카테고리의 다른 글

[C++] 예외 처리(Exception handling)  (0) 2024.06.28
[C++] 템플릿 특수화와 비타입 파라미터  (0) 2024.06.28
[C++] 정사각형-직사각형 문제  (0) 2024.06.28
[C++] 다중 상속과 다이아몬드 문제  (0) 2024.06.28
[C++] 객체 지향 프로그래밍의 4대 원칙(원리)  (0) 2024.06.28
'Programming Language(Sub)/C++' 카테고리의 다른 글
  • [C++] 예외 처리(Exception handling)
  • [C++] 템플릿 특수화와 비타입 파라미터
  • [C++] 정사각형-직사각형 문제
  • [C++] 다중 상속과 다이아몬드 문제
lumana
lumana
배움을 나누는 공간 https://github.com/bebeis
  • lumana
    Brute force Study
    lumana
  • 전체
    오늘
    어제
    • 분류 전체보기 (457)
      • Software Development (27)
        • Performance (0)
        • TroubleShooting (1)
        • Refactoring (0)
        • Test (8)
        • Code Style, Convetion (0)
        • DDD (0)
        • Software Engineering (18)
      • Java (71)
        • Basic (5)
        • Core (21)
        • Collection (7)
        • 멀티스레드&동시성 (13)
        • IO, Network (8)
        • Reflection, Annotation (3)
        • Modern Java(8~) (12)
        • JVM (2)
      • Spring (53)
        • Framework (12)
        • MVC (23)
        • Transaction (3)
        • AOP (11)
        • Boot (0)
        • AI (0)
      • DB Access (1)
        • Jdbc (1)
        • JdbcTemplate (0)
        • JPA (14)
        • Spring Data JPA (0)
        • QueryDSL (0)
      • Computer Science (130)
        • Data Structure (27)
        • OS (14)
        • Database (10)
        • Network (21)
        • 컴퓨터구조 (6)
        • 시스템 프로그래밍 (23)
        • Algorithm (29)
      • HTTP (8)
      • Infra (1)
        • Docker (1)
      • 프로그래밍언어론 (15)
      • Programming Language(Sub) (77)
        • Kotlin (1)
        • Python (25)
        • C++ (51)
        • JavaScript (0)
      • FE (11)
        • HTML (1)
        • CSS (9)
        • React (0)
        • Application (1)
      • Unix_Linux (0)
        • Common (0)
      • PS (13)
        • BOJ (7)
        • Tip (3)
        • 프로그래머스 (0)
        • CodeForce (0)
      • Book Review (4)
        • Clean Code (4)
      • Math (3)
        • Linear Algebra (3)
      • AI (7)
        • DL (0)
        • ML (0)
        • DA (0)
        • Concepts (7)
      • 프리코스 (4)
      • Project Review (6)
      • LegacyPosts (11)
      • 모니터 (0)
      • Diary (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.4
lumana
[C++] 함수 템플릿과 클래스 템플릿
상단으로

티스토리툴바