C++20에서는 클래스 템플릿의 인자 추론(Class Template Argument Deduction, CTAD)이 더욱 강화되어, 클래스 템플릿을 사용할 때 템플릿 인자를 명시적으로 지정하지 않아도 컴파일러가 자동으로 추론할 수 있게 되었습니다. 이번 글에서는 CTAD의 개념과 사용법, 그리고 이전 버전과 비교하여 어떻게 개선되었는지 알아보겠습니다.
클래스 템플릿 인자 추론이란 무엇인가요?
클래스 템플릿 인자 추론(Class Template Argument Deduction, CTAD)은 클래스 템플릿을 인스턴스화할 때 템플릿 인자를 명시적으로 지정하지 않아도, 컴파일러가 생성자의 인자 등을 기반으로 템플릿 인자를 자동으로 추론하는 기능입니다. 이는 C++17에서 도입되었지만, C++20에서는 사용자 정의 클래스에서도 추론 가이드(Deduction Guide)를 통해 더욱 유연하게 활용할 수 있게 되었습니다.
이전 버전에서는 어떻게 했나요?
C++17 이전에는 클래스 템플릿을 인스턴스화할 때 항상 템플릿 인자를 명시적으로 지정해야 했습니다.
예제: 기존 방식의 클래스 템플릿 사용
template <typename T>
class Wrapper {
public:
Wrapper(T value) : value_(value) {}
T get() const { return value_; }
private:
T value_;
};
int main() {
Wrapper<int> w(42); // 템플릿 인자 <int>를 명시적으로 지정
std::cout << w.get() << "\n"; // 출력: 42
return 0;
}
- 문제점:
- 클래스 템플릿을 사용할 때마다 템플릿 인자를 명시적으로 지정해야 하므로 코드가 장황해집니다.
- 특히 생성자의 인자로부터 타입을 유추할 수 있음에도 불구하고, 이를 활용하지 못했습니다.
C++20의 클래스 템플릿 인자 추론을 사용한 개선
C++20에서는 컴파일러가 생성자의 인자 등을 기반으로 템플릿 인자를 자동으로 추론할 수 있습니다. 또한 사용자 정의 클래스에서도 추론 가이드를 작성하여 원하는 방식으로 템플릿 인자를 추론하도록 할 수 있습니다.
예제: 클래스 템플릿 인자 추론 사용
template <typename T>
class Wrapper {
public:
Wrapper(T value) : value_(value) {}
T get() const { return value_; }
private:
T value_;
};
int main() {
Wrapper w(42); // 템플릿 인자 <int>를 추론
std::cout << w.get() << "\n"; // 출력: 42
return 0;
}
- Wrapper<int> 대신 Wrapper로 간단하게 선언할 수 있습니다.
- 컴파일러는 생성자의 인자 42를 보고 T가 int임을 추론합니다.
어떻게 좋아졌나요?
- 코드 간결화: 템플릿 인자를 명시적으로 지정할 필요가 없어 코드가 깔끔해집니다.
- 유연성 향상: 생성자의 인자 타입에 따라 템플릿 인자를 자동으로 추론하므로, 다양한 타입에 대해 코드의 재사용성이 높아집니다.
- 가독성 개선: 불필요한 템플릿 인자 표기를 줄여 코드의 가독성이 향상됩니다.
상세한 예제와 비교
1. 표준 컨테이너와 CTAD
C++17부터 표준 컨테이너에서도 CTAD가 지원되어, 템플릿 인자를 생략할 수 있었습니다.
#include <vector>
int main() {
std::vector vec = {1, 2, 3}; // std::vector<int>로 추론
return 0;
}
2. 사용자 정의 클래스에서의 추론 가이드
C++20에서는 사용자 정의 클래스에서도 추론 가이드를 통해 CTAD를 커스터마이징할 수 있습니다.
예제: 추론 가이드 사용
template <typename T>
class Pair {
public:
Pair(T first, T second) : first_(first), second_(second) {}
T first() const { return first_; }
T second() const { return second_; }
private:
T first_;
T second_;
};
// 추론 가이드 작성
template <typename T1, typename T2>
Pair(T1, T2) -> Pair<std::common_type_t<T1, T2>>;
int main() {
Pair p(3, 4.5); // T를 double로 추론
std::cout << p.first() << ", " << p.second() << "\n"; // 출력: 3, 4.5
return 0;
}
- 추론 가이드를 통해 Pair 클래스의 템플릿 인자를 T1과 T2의 공통 타입으로 추론하도록 지정했습니다.
- 따라서 int와 double을 인자로 전달하면 T는 double로 추론됩니다.
3. 복잡한 생성자와 CTAD
template <typename T>
class Container {
public:
Container(std::initializer_list<T> list) : data_(list) {}
// 다른 생성자들...
private:
std::vector<T> data_;
};
// 추론 가이드 작성
template <typename T>
Container(std::initializer_list<T>) -> Container<T>;
int main() {
Container c{1, 2, 3}; // T를 int로 추론
return 0;
}
- std::initializer_list를 인자로 받는 생성자를 사용하여 템플릿 인자를 추론합니다.
- 추론 가이드를 통해 정확한 타입을 추론할 수 있습니다.
주의 사항
명확한 타입 추론 필요: 컴파일러가 템플릿 인자를 추론할 수 있어야 합니다. 모호한 경우에는 추론이 실패할 수 있습니다.
Wrapper w1(42); // T를 int로 추론
Wrapper w2(3.14); // T를 double로 추론
Wrapper w3("Hello"); // T를 const char*로 추론
Wrapper w4(); // 오류: 생성자 인자가 없으므로 추론 불가
추론 가이드의 정확성: 잘못된 추론 가이드를 작성하면 예상치 못한 타입으로 추론될 수 있습니다.
// 잘못된 추론 가이드
template <typename T> Pair(T, T) -> Pair<int>;
Pair p(3, 4.5); // T를 int로 추론하므로 데이터 손실 발생
복잡한 생성자: 생성자가 오버로딩되어 있거나, 인자가 복잡한 경우에는 추론 가이드가 필수적입니다.
요약
C++20의 클래스 템플릿 인자 추론은 이전 버전에서 불편했던 템플릿 인자 명시를 생략하고, 컴파일러가 자동으로 타입을 추론할 수 있게 해줍니다. 이를 통해 코드의 가독성과 유연성이 향상되며, 개발자의 코딩 시간을 절약할 수 있습니다. 특히 사용자 정의 클래스에서도 추론 가이드를 활용하여 원하는 방식으로 타입을 추론할 수 있어, 템플릿 프로그래밍이 더욱 편리해졌습니다.
참고 자료:
'개발 이야기 > C++' 카테고리의 다른 글
[C++20 새기능 소개] [[likely]]와 [[unlikely]] 속성 (0) | 2024.12.08 |
---|---|
[C++20 새기능 소개] constexpr의 컨테이너 (std::vector, std::string) 지원 (0) | 2024.12.08 |
[C++20 새기능 소개] 개선된 <chrono> (0) | 2024.12.06 |
C++26 지금까지 알려진 사실 (0) | 2024.12.06 |
[C++20 새기능 소개] using enum (0) | 2024.12.05 |