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 비타입 템플릿 매개변수는 템플릿 프로그래밍의 표현력을 크게 향상시켰습니다. 이전에는 제한된 타입만을 비타입 템플릿 매개변수로 사용할 수 있었지만, 이제는 다양한 타입의 값을 매개변수로 사용하여 더욱 유연한 코드를 작성할 수 있습니다. 이를 통해 템플릿 메타프로그래밍이 더욱 강력해지고, 코드의 간결성과 가독성이 향상되었습니다.
참고 자료:
'개발 이야기 > C++' 카테고리의 다른 글
[C++23 새기능 소개] std::stacktrace 라이브러리 (0) | 2024.12.08 |
---|---|
[C++23 새기능 소개] std::print와 std::println 함수 (0) | 2024.12.08 |
[C++20 새기능 소개] [[likely]]와 [[unlikely]] 속성 (0) | 2024.12.08 |
[C++20 새기능 소개] constexpr의 컨테이너 (std::vector, std::string) 지원 (0) | 2024.12.08 |
[C++20 새기능 소개] 클래스 템플릿의 인자 추론 (Class Template Argument Deduction, CTAD) (0) | 2024.12.07 |