Menu
Coddy logo textTech

템플릿 특수화

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

때때로 제네릭 템플릿이 모든 타입에 대해 잘 작동하지 않을 수 있습니다. 예를 들어, >를 사용하여 C 스타일 문자열을 비교하면 실제 텍스트가 아니라 포인터 주소를 비교하게 됩니다. 템플릿 특수화(Template specialization)를 사용하면 다른 모든 타입에 대해서는 제네릭 버전을 유지하면서 특정 타입에 대해서만 사용자 정의 구현을 제공할 수 있습니다.

완전 특수화(full specialization)는 특정 타입에 대해 전체 템플릿을 대체합니다. 빈 템플릿 매개변수 목록을 사용하여 이를 선언하고 구체적인 타입을 지정합니다:

// 기본 템플릿
template <typename T>
class Printer {
public:
    void print(T value) {
        std::cout << value << std::endl;
    }
};

// const char*에 대한 전체 특수화
template <>
class Printer<const char*> {
public:
    void print(const char* value) {
        std::cout << "String: " << value << std::endl;
    }
};

Printer<int> intPrinter;
intPrinter.print(42);           // 출력: 42

Printer<const char*> strPrinter;
strPrinter.print("hello");      // 출력: String: hello

함수 템플릿 또한 특수화될 수 있습니다:

template <typename T>
bool isEqual(T a, T b) {
    return a == b;
}

template <>
bool isEqual<const char*>(const char* a, const char* b) {
    return std::strcmp(a, b) == 0;
}

isEqual(5, 5);              // 일반 버전을 사용함
isEqual("hi", "hi");        // 특수화된 버전을 사용함

컴파일러는 항상 가장 구체적인 일치를 선호합니다. 사용 중인 정확한 타입에 대해 특수화(specialization)가 존재하는 경우, 제네릭 템플릿보다 해당 특수화가 선택됩니다.

challenge icon

챌린지

쉬움

템플릿 특수화(template specialization)를 통해 일반적인 타입에 대한 기본 동작을 유지하면서 특정 타입에 대해 동작을 맞춤 설정하는 방법을 보여주는 타입 인식 포맷터 시스템을 구축해 보겠습니다.

템플릿 코드를 정리하기 위해 두 개의 파일을 생성합니다:

  • Formatter.h: 값을 표시하기 위해 포맷팅하는 Formatter라는 클래스 템플릿을 정의합니다. 기본 템플릿은 모든 타입에서 작동해야 하지만, 커스텀 처리가 필요한 타입에 대해서는 특수화된 버전을 만듭니다.

    기본 Formatter 템플릿은 다음을 포함해야 합니다:

    • T 타입의 값을 받아 Value: <value>를 출력하는 format() 메서드

    1 또는 0 대신 사람이 읽을 수 있는 텍스트를 출력하는 bool 타입에 대한 완전 특수화를 생성합니다:

    • format() 메서드는 Boolean: true 또는 Boolean: false를 출력해야 합니다.

    문자열 주위에 따옴표를 추가하는 const char* 타입에 대한 완전 특수화를 생성합니다:

    • format() 메서드는 String: "<value>"를 출력해야 합니다.

    또한 동일한 타입의 두 값을 받아 Pair: [<first>, <second>] 형식으로 함께 출력하는 formatPair라는 함수 템플릿을 생성합니다.

    각 문자열을 따옴표로 감싸는 const char* 타입에 대한 formatPair 특수화를 생성합니다: Pair: ["<first>", "<second>"]

  • main.cpp: 네 개의 입력(각각 별도의 줄에 있음)을 읽습니다:
    1. 정수
    2. 실수(double)
    3. 문자열 형태의 불리언 ("true" 또는 "false")
    4. 문자열 값

    적절한 Formatter 객체를 생성하고 각 타입에 대해 format()을 호출하여 포맷터를 시연합니다:

    1. Formatter<int>를 사용하여 정수 포맷팅
    2. Formatter<double>를 사용하여 실수 포맷팅
    3. Formatter<bool>를 사용하여 불리언 포맷팅 (먼저 문자열 입력을 bool로 변환)
    4. Formatter<const char*>를 사용하여 문자열 포맷팅

    그런 다음 함수 템플릿 특수화를 시연합니다:

    1. 두 개의 정수 10과 20으로 formatPair 호출
    2. 두 개의 C-문자열 "hello""world"formatPair 호출

예를 들어, 입력이 42, 3.14, "true", "Hello"인 경우:

Value: 42
Value: 3.14
Boolean: true
String: "Hello"
Pair: [10, 20]
Pair: ["hello", "world"]

기본 템플릿이 정수와 실수를 동일하게 처리하는 반면, boolconst char*에 대한 특수화된 버전은 커스텀 포맷팅을 제공하는 방식에 주목하세요. 컴파일러는 사용하는 각 타입에 대해 가장 구체적으로 일치하는 항목을 자동으로 선택합니다.

치트 시트

템플릿 특수화(Template specialization)를 사용하면 다른 모든 타입에 대해서는 일반적인 버전을 유지하면서, 특정 타입에 대해서만 사용자 정의 구현을 제공할 수 있습니다.

전체 특수화(Full Specialization) 구문

빈 템플릿 매개변수 목록인 template <>를 사용하여 특수화를 선언하고 구체적인 타입을 지정합니다:

// Primary template
template <typename T>
class Printer {
public:
    void print(T value) {
        std::cout << value << std::endl;
    }
};

// Full specialization for const char*
template <>
class Printer<const char*> {
public:
    void print(const char* value) {
        std::cout << "String: " << value << std::endl;
    }
};

함수 템플릿 특수화

함수 템플릿 또한 특수화할 수 있습니다:

template <typename T>
bool isEqual(T a, T b) {
    return a == b;
}

template <>
bool isEqual<const char*>(const char* a, const char* b) {
    return std::strcmp(a, b) == 0;
}

컴파일러 선택

컴파일러는 항상 가장 구체적으로 일치하는 항목을 선호합니다. 사용 중인 정확한 타입에 대한 특수화가 존재하는 경우, 일반 템플릿보다 해당 특수화가 선택됩니다.

직접 해보기

#include <iostream>
#include <string>
#include "Formatter.h"

using namespace std;

int main() {
    // 입력 읽기
    int intVal;
    double doubleVal;
    string boolStr;
    string strVal;
    
    cin >> intVal;
    cin >> doubleVal;
    cin >> boolStr;
    cin >> strVal;
    
    // string을 bool로 변환
    bool boolVal = (boolStr == "true");
    
    // TODO: Formatter<int>를 생성하고 정수를 포맷팅하세요
    
    // TODO: Formatter<double>을 생성하고 실수를 포맷팅하세요
    
    // TODO: Formatter<bool>을 생성하고 불리언을 포맷팅하세요
    
    // TODO: Formatter<const char*>를 생성하고 문자열을 포맷팅하세요
    // Hint: const char*를 얻으려면 strVal.c_str()을 사용하세요
    
    // TODO: 두 개의 정수 10과 20으로 formatPair를 호출하세요
    
    // TODO: 두 개의 C-strings "hello"와 "world"로 formatPair를 호출하세요
    
    return 0;
}
quiz icon실력 점검

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

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