제네릭 프로그래밍 (Generic Programming)

  • 데이터 형식에 의존하지 않고, 하나의 값이 여러 다른 데이터 타입들을 가질 수 있는 기술에 중점을 두어 재사용성을 높일 수 있는 프로그래밍 방식.

  • 여러가지 유용한 소프트웨어 컴포넌트들을 체계적으로 융합하는 방법을 연구하는 것으로, 그 목적은 알고리즘, 데이터 구조, 메모리 할당 메커니즘, 그리고 기타 여러 소프트웨어적인 장치들을 발전시켜 이들의 재사용성, 모듈화, 사용 편이성을 보다 높은 수준으로 끌어올리고자 하는 것.

  • 프로그래밍 패러다임의 하나로, 다양한 데이터 타입에 대해 동일한 연산을 수행할 수 있는 다형성을 보장함.

  • C++ 에서는 템플릿(template)으로 선언한 자료형을 사용하면 제네릭 프로그래밍을 할 수 있음.

    • 아래와 같은 방법을 함수 템플릿(Function Template)이라고 함.

#include <iostream>
using namespace std;

template <typename T>

T add(T a, T b) {
    return a + b;
}

int main() {
    int x1 = 3, y1 = 5;
    cout << add(x1, y1) << endl; // 8
    
    double x2 = 3.2, y2 = 4.5;
    cout << add(x2, y2) << endl; // 7.7
    
    return 0;
}
  • C++에서 일반적인 자료 구조와 알고리즘을 구현해 놓은 라이브러리 집합을 제공하는데, 이를 표준 템플릿 라이브러리(Standard Template Library, STL)이라고 함.

    • 지원하는 자료구조에는 vector, map, set 등이 있으며, 여러 가지 탐색 변경 알고리즘을 지원함.

    • 각 자료구조의 데이터 타입은 템플릿으로 선언되어 있어서 자료구조마다 다양한 데이터 타입에 대해 사용 가능.

    • 자료의 유형에 상관없이 구현되어 있어 generic 이라고 말하기도 함.

template < class T, class Alloc = allocator<T> > class vector; // generic template
  • C++에서 template <typename T> 선언 시, 컴파일 될 때 T가 구체적인 타입으로 해석되어 지는데, 이는 사용된 모든 타입에 대해 인스턴스화를 진행하기 때문임.

template <typename T>
T max(T a, T b) { return a > b ? a : b; }

// 위 함수는 컴파일 시점에 인스턴스화가 진행되어 아래의 함수들이 생성됨.
int Max(int a, int b) { return a > b ? a : b; }
float Max(float a, float b) { return a > b ? a : b; }
double Max(double a, double b) { return a > b ? a : b; }
// ...

 

클래스 템플릿 (Class Template)

  • 템플릿 적용 전: 하나의 데이터 타입만 허용하는 클래스

class Data {
private:
    int data;
public:
    Data(int d) { data = d; }
    void setData(int d) { data = d; }
    int getData() const { return data; }
};
  • 템플릿 적용 후: 여러 데이터 타이을 허용하는 클래스

template <typename T>

class Data {
private:
    T data;
public:
    Data(T d) { data = d; }
    void setData(T d) { data = d; }
    T getData() const { return d; }
};
  • 템플릿을 정의할 때 typename과 class 키워드가 있음. 보통은 둘 다 사용 가능.

template <typename T1>
template <class T2>
  • 그러나, 둘을 혼용할 수 없는 특수한 경우가 있음.

  • 의존적인 형(dependent type)인 경우, typename만 사용 가능.

    • 즉, 다른 템플릿 타입과 관련된 타입을 사용하는 경우.

    • 중첩 의존 타입 이름(nested dependent typename)을 식별하는 용도는 typename 키워드이며, 클래스 내부 서브 타입을 지정할 때 사용된다.

// typename만 사용 가능한 경우
template <typename param_t>

class Foo {
    typedef typename param_t::baz sub_t;
};
  • 템플릿 타입에 대해 템플릿을 정의하는 경우, class만 사용 가능.

    • template template 구문에서는 classa만 사용되며, 템플릿을 인스턴스화 할 때에도 class만 사용됨.

    • typename은 템플릿 내부에서만 사용되고, 초기화 리스트 및 기본 클래스 리스트에서는 사용 불가.

// class만 사용 가능한 경우
template <template <typename, typename> class Container, typename Type>
template class Foo<int>;

 

+ Recent posts