C++ STL: 8장 - STL과 고급 템플릿 기법

2025. 2. 26. 18:17프로그래밍 언어/C++ STL

8.1 템플릿의 기본 개념

템플릿은 일반화 프로그래밍(generic programming)을 지원하기 위해 C++에서 제공하는 강력한 기능입니다. STL은 템플릿을 기반으로 설계되어, 컨테이너, 알고리즘, 반복자 등이 다양한 데이터 타입에서 동작할 수 있도록 일반화되어 있습니다.

8.1.1 함수 템플릿

  • 다양한 타입의 데이터를 처리하는 함수 작성에 사용됩니다.

예제:

#include <iostream>

template <typename T>
T add(T a, T b) {
    return a + b;
}

int main() {
    std::cout << add(5, 3) << "\n";      // 정수
    std::cout << add(5.5, 2.5) << "\n";  // 실수
    return 0;
}

8.1.2 클래스 템플릿

  • 데이터 타입에 의존하지 않는 클래스 작성에 사용됩니다.

예제:

#include <iostream>

template <typename T>
class Box {
private:
    T value;
public:
    Box(T v) : value(v) {}
    void display() { std::cout << value << "\n"; }
};

int main() {
    Box<int> intBox(123);
    Box<std::string> strBox("Hello");

    intBox.display();
    strBox.display();

    return 0;
}

8.2 템플릿 특수화

템플릿 특수화는 특정 타입에 대해 일반 템플릿과는 다른 동작을 정의할 때 사용됩니다.

8.2.1 함수 템플릿 특수화

  • 특정 타입에 대해 별도의 구현을 제공합니다.

예제:

#include <iostream>

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

// 함수 템플릿 특수화 (const char* 타입)
template <>
const char* max(const char* a, const char* b) {
    return (std::strcmp(a, b) > 0) ? a : b;
}

int main() {
    std::cout << max(10, 20) << "\n";            // 정수
    std::cout << max("apple", "banana") << "\n"; // 문자열
    return 0;
}

8.2.2 클래스 템플릿 특수화

  • 특정 타입에 대해 별도의 클래스 정의를 제공합니다.

예제:

#include <iostream>

template <typename T>
class Printer {
public:
    void print(T value) { std::cout << value << "\n"; }
};

// 클래스 템플릿 특수화 (bool 타입)
template <>
class Printer<bool> {
public:
    void print(bool value) {
        std::cout << (value ? "true" : "false") << "\n";
    }
};

int main() {
    Printer<int> intPrinter;
    Printer<bool> boolPrinter;

    intPrinter.print(123);
    boolPrinter.print(true);

    return 0;
}

8.3 가변 길이 템플릿 (Variadic Templates)

C++11부터 도입된 가변 길이 템플릿은 임의의 개수의 인자를 처리할 수 있는 템플릿 작성에 유용합니다.

8.3.1 가변 길이 함수 템플릿

예제:

#include <iostream>

template <typename... Args>
void printAll(Args... args) {
    (std::cout << ... << args) << "\n"; // Fold expression
}

int main() {
    printAll(1, 2, 3.5, "Hello", true);
    return 0;
}

8.3.2 가변 길이 클래스 템플릿

예제:

#include <iostream>
#include <tuple>

template <typename... Args>
class MultiContainer {
private:
    std::tuple<Args...> data;
public:
    MultiContainer(Args... args) : data(args...) {}
    void print() { std::apply([](auto&&... args) { ((std::cout << args << " "), ...); }, data); }
};

int main() {
    MultiContainer<int, double, std::string> container(1, 2.5, "Hello");
    container.print();
    return 0;
}

8.4 템플릿 메타프로그래밍 (Template Metaprogramming)

템플릿 메타프로그래밍은 컴파일 타임에 코드를 생성하거나 계산을 수행하는 고급 기법입니다. STL의 일부 구성 요소는 이러한 기법을 사용해 설계되었습니다.

8.4.1 기본 템플릿 재귀

예제:

#include <iostream>

template <int N>
struct Factorial {
    static constexpr int value = N * Factorial<N - 1>::value;
};

template <>
struct Factorial<0> {
    static constexpr int value = 1;
};

int main() {
    std::cout << "Factorial of 5: " << Factorial<5>::value << "\n";
    return 0;
}

Note: 위 예제는 컴파일 타임 계산을 보여주는 데 유용하지만, 큰 값에 대해 사용하면 컴파일러의 재귀 제한에 걸릴 수 있습니다. 따라서 적절한 크기에서 사용하는 것이 중요합니다.

8.4.2 std::enable_if를 활용한 SFINAE

  • SFINAE(Substitution Failure Is Not An Error)를 사용하여 특정 조건에 따라 템플릿 활성화 여부를 결정합니다.
  • SFINAE는 템플릿 인자에 대한 조건을 기반으로 유효하지 않은 템플릿 인자를 무시하는 메커니즘입니다.

예제:

#include <iostream>
#include <type_traits>

template <typename T>
typename std::enable_if<std::is_integral<T>::value, T>::type
increment(T value) {
    return value + 1;
}

int main() {
    std::cout << increment(5) << "\n";  // 정수는 허용
    // std::cout << increment(5.5) << "\n";  // 컴파일 에러
    return 0;
}

Note: std::enable_if를 사용하면 템플릿의 유효성을 조건부로 제어할 수 있습니다. C++20에서는 std::enable_if 대신 concepts를 활용해 더 간단하고 명확하게 조건을 정의할 수 있습니다.


8.5 STL에서 템플릿 기법 활용

8.5.1 STL 컨테이너의 템플릿 사용

  • STL 컨테이너는 대부분 템플릿 클래스로 설계되어 있습니다.
  • 예: std::vector<T>, std::map<Key, Value>.

8.5.2 STL 알고리즘과 템플릿

  • STL 알고리즘은 템플릿 함수로 설계되어, 어떤 컨테이너 타입에도 적용 가능합니다.

예제:

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> vec = {3, 1, 4, 1, 5};
    std::sort(vec.begin(), vec.end());

    for (int n : vec) {
        std::cout << n << " ";
    }
    return 0;
}

결론

템플릿은 C++의 강력한 기능 중 하나로, STL의 근간을 이루고 있습니다. 기본 템플릿부터 고급 기법인 가변 길이 템플릿, 메타프로그래밍까지 이해한다면, 더욱 효율적이고 유연한 코드를 작성할 수 있습니다.