Menu
Coddy logo textTech

함수 템플릿

Coddy C++ 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨 — 104개 중 64번째.

두 개의 정수 중 최댓값을 찾는 함수를 작성하다가, double이나 string 타입에 대해서도 동일한 로직이 필요하다는 것을 깨닫는 상황을 상상해 보세요. 템플릿이 없다면 각 타입마다 거의 동일한 함수를 일일이 작성해야 할 것입니다. 함수 템플릿은 로직을 한 번만 작성하면 컴파일러가 각 타입에 맞는 버전을 자동으로 생성하게 함으로써 이 문제를 해결해 줍니다.

함수 템플릿은 template 키워드 뒤에 꺾쇠괄호 안의 템플릿 매개변수가 오는 형식을 사용합니다:

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

int main() {
    std::cout << maximum(5, 3) << std::endl;       // int 버전 사용
    std::cout << maximum(3.14, 2.71) << std::endl; // double 버전 사용
    std::cout << maximum('a', 'z') << std::endl;   // char 버전 사용
}

컴파일러는 각 호출을 검사하고 해당 특정 타입에 대한 구체적인 함수를 생성합니다. 이 과정을 템플릿 인스턴스화(template instantiation)라고 합니다. 필요할 때 타입을 명시적으로 지정할 수도 있습니다:

std::cout << maximum<double>(5, 3.14) << std::endl;  // double 버전을 강제합니다

템플릿은 여러 개의 타입 매개변수를 가질 수 있어, 더욱 유연한 설계를 가능하게 합니다:

template <typename T, typename U>
void printPair(T first, U second) {
    std::cout << first << ", " << second << std::endl;
}

printPair(42, "hello");    // T=int, U=const char*
printPair(3.14, 100);      // T=double, U=int

함수 템플릿은 컴파일 타임 다형성을 제공합니다. 즉, 타입은 런타임이 아니라 코드가 컴파일될 때 결정됩니다. 이는 가상 함수와 비교하여 런타임 오버헤드가 전혀 없음을 의미하며, 템플릿을 성능이 중요한 제네릭 코드에 이상적인 선택으로 만듭니다.

challenge icon

챌린지

쉬움

함수 템플릿을 사용하여 호환되는 모든 타입에서 작동하는 재사용 가능한 연산을 만드는 유틸리티 툴킷을 만들어 보겠습니다. 제네릭 함수를 헤더 파일에 정리하고 메인 프로그램에서 그 유연성을 입증하게 됩니다.

두 개의 파일을 생성합니다:

  • MathUtils.h: 일반적인 연산을 수행하는 함수 템플릿 모음을 정의합니다:

    minimum — 동일한 타입의 두 값을 받아 더 작은 값을 반환하는 템플릿 함수입니다.

    clamp — 값, 하한값(low bound), 상한값(high bound)의 세 가지 매개변수를 받는 템플릿 함수입니다. 이 함수는 범위 내로 제한된 값을 반환합니다(값이 하한보다 작으면 하한을, 상한보다 크면 상한을, 그렇지 않으면 값 자체를 반환합니다).

    swapValues — 동일한 타입의 두 참조(reference)를 받아 그 값을 서로 교환하는 템플릿 함수입니다.

  • main.cpp: 6개의 입력을 읽습니다 (각각 별도의 줄에 입력됨):

    1. 첫 번째 정수
    2. 두 번째 정수
    3. 제한(clamp)할 double 값
    4. 하한값 (double)
    5. 상한값 (double)
    6. 문자 하나

    다음 작업을 통해 템플릿을 시연합니다:

    1. 두 정수의 최솟값을 찾아 출력합니다: Min of <a> and <b>: <result>
    2. 문자 'm'과 입력받은 문자의 최솟값을 찾아 출력합니다: Min of m and <char>: <result>
    3. double 값을 제한(clamp)하고 출력합니다: Clamp <value> to [<low>, <high>]: <result>
    4. 첫 번째 정수를 [0, 100] 범위로 제한(clamp)하고 출력합니다: Clamp <value> to [0, 100]: <result>
    5. 두 정수를 교환(swap)하고 출력합니다: After swapValues: <a>, <b>

예를 들어, 입력값이 25, 10, 3.7, 1.0, 5.0, z인 경우:

Min of 25 and 10: 10
Min of m and z: m
Clamp 3.7 to [1, 5]: 3.7
Clamp 25 to [0, 100]: 25
After swapValues: 10, 25

각 템플릿 함수가 정수, double, 문자에서 어떻게 원활하게 작동하는지 확인해 보세요. 컴파일러는 사용하는 각 타입에 대해 적절한 버전을 생성합니다. swapValues 함수는 참조를 통해 원래 변수를 수정해야 하며, 이는 템플릿이 일반 함수와 마찬가지로 참조 매개변수와 함께 작동함을 보여줍니다.

치트 시트

함수 템플릿을 사용하면 여러 타입에서 작동하는 제네릭 함수를 작성할 수 있습니다. template 키워드 뒤에 템플릿 매개변수를 사용하여 정의합니다:

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

컴파일러는 템플릿 인스턴스화(template instantiation)를 통해 타입별 버전을 자동으로 생성합니다:

maximum(5, 3);        // int 버전을 생성합니다
maximum(3.14, 2.71);  // double 버전을 생성합니다
maximum('a', 'z');    // char 버전을 생성합니다

필요한 경우 타입을 명시적으로 지정할 수 있습니다:

maximum<double>(5, 3.14);  // double 버전을 강제로 사용합니다

템플릿은 여러 개의 타입 매개변수를 지원합니다:

template <typename T, typename U>
void printPair(T first, U second) {
    std::cout << first << ", " << second << std::endl;
}

printPair(42, "hello");  // T=int, U=const char*

템플릿은 원본 값을 수정하기 위해 참조 매개변수와 함께 사용할 수 있습니다:

template <typename T>
void swapValues(T& a, T& b) {
    T temp = a;
    a = b;
    b = temp;
}

함수 템플릿은 런타임 오버헤드 없이 컴파일 타임 다형성을 제공하므로, 성능이 중요한 제네릭 코드를 작성하는 데 이상적입니다.

직접 해보기

#include <iostream>
#include "MathUtils.h"
using namespace std;

int main() {
    // 입력 읽기
    int a, b;
    double value, low, high;
    char ch;
    
    cin >> a;
    cin >> b;
    cin >> value;
    cin >> low;
    cin >> high;
    cin >> ch;
    
    // TODO: minimum 템플릿을 사용하여 두 정수의 최솟값 찾기
    // 출력: "Min of <a> and <b>: <result>"
    
    // TODO: minimum 템플릿을 사용하여 'm'과 입력된 문자의 최솟값 찾기
    // 출력: "Min of m and <char>: <result>"
    
    // TODO: double 값에 clamp 템플릿 사용하기
    // 출력: "Clamp <value> to [<low>, <high>]: <result>"
    
    // TODO: [0, 100] 범위의 첫 번째 정수에 clamp 템플릿 사용하기
    // 출력: "Clamp <value> to [0, 100]: <result>"
    
    // TODO: 두 정수에 swapValues 템플릿 사용하기
    // 출력: "After swapValues: <a>, <b>"
    
    return 0;
}
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

객체 지향 프로그래밍의 모든 레슨