변수 템플릿(Variable template)
변수 템플릿(Variable template)
타입별로 값이 달라지는 상수, 예를 들어 pi<T>처럼 타입마다 다른 원주율을 만들고 싶다면 어떻게 해야 할까요? 함수 템플릿이나 클래스의 정적 멤버를 쓰는 방법도 있지만, C++14부터는 **변수 템플릿(variable template)**으로 변수 자체를 템플릿으로 만들 수 있어요. 변수 템플릿은 변수나 정적 데이터 멤버의 집합(family)을 정의해요.
출처: cppreference
본문
문법
template < parameter-list > variable-declaration |
(1) | |
template < parameter-list > requires constraint variable-declaration |
(2) | (C++20부터) |
| 자리 | 의미 |
|---|---|
| variable-declaration | 변수의 선언. 선언된 변수 이름이 템플릿 이름이 돼요. |
| parameter-list | 비어 있지 않은 템플릿 매개변수의 쉼표 구분 목록. 각각은 비타입 매개변수, 타입 매개변수, 템플릿 매개변수, 또는 그것들 중 하나의 매개변수 팩이에요. |
| constraint | 이 변수 템플릿이 받아들이는 템플릿 매개변수를 제한하는 제약 표현식 |
동작 방식(Explanation)
변수 템플릿에서 인스턴스화된 변수를 **인스턴스화된 변수(instantiated variable)**라고 불러요. 정적 데이터 멤버 템플릿에서 인스턴스화된 정적 데이터 멤버는 **인스턴스화된 정적 데이터 멤버(instantiated static data member)**라고 해요.
변수 템플릿은 네임스페이스 스코프의 템플릿 선언으로 도입될 수 있고, 이때 variable-declaration이 변수를 선언해요.
template<class T>
constexpr T pi = T(3.1415926535897932385L); // 변수 템플릿
template<class T>
T circular_area(T r) // 함수 템플릿
{
return pi<T> * r * r; // pi<T>는 변수 템플릿의 인스턴스화
}
클래스 스코프에서 쓰이면, 변수 템플릿은 정적 데이터 멤버 템플릿(static data member template)을 선언해요.
using namespace std::literals;
struct matrix_constants
{
template<class T>
using pauli = hermitian_matrix<T, 2>; // 별칭 템플릿
template<class T> // 정적 데이터 멤버 템플릿
static constexpr pauli<T> sigmaX = {{0, 1}, {1, 0}};
template<class T>
static constexpr pauli<T> sigmaY = {{0, -1i}, {1i, 0}};
template<class T>
static constexpr pauli<T> sigmaZ = {{1, 0}, {0, -1}};
};
다른 정적 멤버와 마찬가지로, 정적 데이터 멤버 템플릿의 정의가 필요할 수 있어요. 그런 정의는 클래스 정의 바깥에 제공돼요. 네임스페이스 스코프에서 정적 데이터 멤버의 템플릿 선언은 클래스 템플릿의 비템플릿 데이터 멤버의 정의일 수도 있어요.
struct limits
{
template<typename T>
static const T min; // 정적 데이터 멤버 템플릿의 선언
};
template<typename T>
const T limits::min = { }; // 정적 데이터 멤버 템플릿의 정의
template<class T>
class X
{
static T s; // 클래스 템플릿의 비템플릿 정적 데이터 멤버 선언
};
template<class T>
T X<T>::s = 0; // 클래스 템플릿의 비템플릿 데이터 멤버의 정의
변수 템플릿이 명시적으로 특수화되거나 명시적으로 인스턴스화되지 않았다면, 변수 템플릿의 특수화가 변수 정의가 존재해야 하는 문맥에서 참조되거나, 정의의 존재가 프로그램의 의미에 영향을 줄 때, 즉 변수가 표현식의 상수 평가에 필요할 때 암시적으로 인스턴스화돼요. (정의가 실제로 쓰이지 않아도 돼요.)
변수의 정의 존재는, 변수가 표현식의 상수 평가에 필요하다면 프로그램의 의미에 영향을 주는 것으로 간주돼요. 상수 평가가 요구되지 않거나, 상수 표현식 평가가 그 정의를 실제로 사용하지 않아도 마찬가지예요.
주의할 점(Notes)
변수 템플릿이 C++14에서 도입되기 전까지, 매개변수화된 변수는 보통 클래스 템플릿의 정적 데이터 멤버나 원하는 값을 반환하는 constexpr 함수 템플릿으로 구현했어요.
변수 템플릿은 템플릿 템플릿 인자(template template argument)로 쓸 수 없어요.
| 기능 테스트 매크로 | 값 | 표준 | 기능 |
|---|---|---|---|
__cpp_variable_templates |
201304L | (C++14) | 변수 템플릿 |
결함 보고(Defect reports)
이전에 발표된 C++ 표준들에 소급 적용된 동작 변경 결함 보고들이 있어요.
| DR | 적용 대상 | 발표 당시 동작 | 올바른 동작 |
|---|---|---|---|
| CWG 2255 | C++14 | 정적 데이터 멤버 템플릿의 특수화가 정적 데이터 멤버인지 불분명했음 | 그렇다 |
더 알아보기
- 함수 템플릿: 타입별로 동작이 달라지는 함수의 집합.
- 클래스 템플릿: 타입별로 멤버가 달라지는 클래스의 집합.
- 별칭 템플릿:
using으로 타입 이름의 집합을 정의하는 방법.