[C++20 새기능 소개] 비타입 템플릿 매개변수에 auto사용

C++20에서는 템플릿 프로그래밍의 표현력과 유연성을 높이기 위해 비타입 템플릿 매개변수에 auto를 사용할 수 있게 되었습니다. 이번 글에서는 auto 비타입 템플릿 매개변수의 개념과 사용법, 그리고 이전 버전과 비교하여 어떻게 개선되었는지 알아보겠습니다.

auto 비타입 템플릿 매개변수란 무엇인가요?

C++20에서는 템플릿 매개변수로 타입이 아닌 값을 받을 때, 그 타입을 auto로 지정할 수 있습니다. 이를 통해 정수형 이외의 타입도 비타입 템플릿 매개변수로 사용할 수 있게 되었습니다. 이는 템플릿 프로그래밍에서 가변적인 값을 더욱 유연하게 처리할 수 있도록 해줍니다.

이전 버전에서는 어떻게 했나요?

C++17까지는 비타입(non-type) 템플릿 매개변수로 정수형 상수, 포인터, 참조 등 제한된 타입만을 사용할 수 있었습니다. 따라서 사용자 정의 타입이나 구조체 등을 비타입 템플릿 매개변수로 사용할 수 없었습니다.

예제: 기존 방식의 비타입 템플릿 매개변수 사용

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() {
    constexpr int result = Factorial<5>::value; // result = 120
    return 0;
}
  • 제한점:
    • N은 정수형 상수여야 합니다.
    • 실수형, 문자열, 사용자 정의 타입 등은 비타입 템플릿 매개변수로 사용할 수 없습니다.

C++20의 auto 비타입 템플릿 매개변수를 사용한 개선

C++20에서는 비타입 템플릿 매개변수의 타입을 auto로 지정하여 컴파일러가 해당 타입을 추론하게 할 수 있습니다. 이를 통해 다양한 타입의 값을 비타입 템플릿 매개변수로 사용할 수 있습니다.

예제: auto 비타입 템플릿 매개변수 사용

template <auto N>
struct Constant {
    static constexpr auto value = N;
};

int main() {
    constexpr int intVal = Constant<42>::value;               // int
    constexpr char charVal = Constant<'A'>::value;            // char
    constexpr bool boolVal = Constant<true>::value;           // bool
    constexpr double doubleVal = Constant<3.14>::value;       // double (C++20부터 가능)
    return 0;
}
  • auto를 사용하여 다양한 타입의 값을 비타입 템플릿 매개변수로 받을 수 있습니다.
  • 컴파일러는 N의 타입을 자동으로 추론합니다.

어떻게 좋아졌나요?

  • 유연성 향상: 정수형뿐만 아니라 실수형, 문자, 열거형, 사용자 정의 리터럴 타입 등을 비타입 템플릿 매개변수로 사용할 수 있습니다.
  • 코드 간결화: 템플릿 매개변수의 타입을 명시적으로 지정할 필요가 없어 코드가 간결해집니다.
  • 표현력 증가: 템플릿 프로그래밍에서 더 다양한 패턴과 로직을 구현할 수 있게 되었습니다.

상세한 예제와 비교

1. 열거형 타입의 비타입 템플릿 매개변수

이전 방식

enum class Color { Red, Green, Blue };

// 불가능: 비타입 템플릿 매개변수로 열거형 사용 불가
// template <Color C>
// struct ColorTraits { /* ... */ };

C++20 방식

enum class Color { Red, Green, Blue };

template <auto C>
struct ColorTraits;

template <>
struct ColorTraits<Color::Red> {
    static constexpr const char* name = "Red";
};

template <>
struct ColorTraits<Color::Green> {
    static constexpr const char* name = "Green";
};

template <>
struct ColorTraits<Color::Blue> {
    static constexpr const char* name = "Blue";
};

int main() {
    std::cout << ColorTraits<Color::Green>::name << "\n"; // 출력: Green
    return 0;
}
  • 열거형 값을 비타입 템플릿 매개변수로 사용할 수 있습니다.

2. 문자열 리터럴의 비타입 템플릿 매개변수

이전 방식

  • 문자열 리터럴은 비타입 템플릿 매개변수로 사용할 수 없었습니다.

C++20 방식

template <auto str>
struct StringWrapper {
    static constexpr const char* value = str;
};

int main() {
    using Greeting = StringWrapper<"Hello, World!">;
    std::cout << Greeting::value << "\n"; // 출력: Hello, World!
    return 0;
}
  • 주의: 문자열 리터럴은 배열이므로, 포인터 타입으로 추론됩니다.
  • 문자열 리터럴의 경우 주소 상수성을 고려해야 합니다.

3. 사용자 정의 리터럴 타입의 비타입 템플릿 매개변수

struct Point {
    int x;
    int y;

    constexpr bool operator==(const Point&) const = default;
};

template <auto P>
struct PointWrapper {
    static constexpr Point value = P;
};

int main() {
    constexpr Point p{3, 4};
    auto distance = PointWrapper<p>::value.x * PointWrapper<p>::value.x +
                    PointWrapper<p>::value.y * PointWrapper<p>::value.y;
    std::cout << "Distance squared: " << distance << "\n"; // 출력: 25
    return 0;
}
  • 사용자 정의 타입도 constexpr로 정의되어 있고, operator==가 constexpr로 정의되어 있으면 비타입 템플릿 매개변수로 사용할 수 있습니다.

주의 사항

  • 타입 요구사항: 비타입 템플릿 매개변수로 사용되는 타입은 **리터럴 타입(literal type)**이어야 합니다.
  • 주소 상수성: 포인터나 참조를 비타입 템플릿 매개변수로 사용할 때는 주소가 컴파일 타임에 상수여야 합니다.
  • operator== 필요성: 사용자 정의 타입을 비타입 템플릿 매개변수로 사용할 때는 operator==가 constexpr로 정의되어 있어야 합니다.

요약

C++20에서의 auto 비타입 템플릿 매개변수는 템플릿 프로그래밍의 표현력을 크게 향상시켰습니다. 이전에는 제한된 타입만을 비타입 템플릿 매개변수로 사용할 수 있었지만, 이제는 다양한 타입의 값을 매개변수로 사용하여 더욱 유연한 코드를 작성할 수 있습니다. 이를 통해 템플릿 메타프로그래밍이 더욱 강력해지고, 코드의 간결성과 가독성이 향상되었습니다.

 

참고 자료:

 

반응형