Template parameters
모든 template 은 하나 이상의 템플릿 매개변수에 의해 매개변수화됩니다.
template-parameter-list ( template declaration syntax 참조)의 각 매개변수는 다음 범주 중 하나에 속합니다:
- 상수 템플릿 매개변수
- 타입 템플릿 매개변수
- 템플릿 템플릿 매개변수
목차 |
상수 템플릿 매개변수
비타입 템플릿 매개변수 로도 알려져 있습니다(아래 참조 ).
| type name (선택 사항) | (1) | ||||||||
type
name
(선택 사항)
=
default
|
(2) | ||||||||
type
...
name
(선택 사항)
|
(3) | (C++11 이후) | |||||||
| type | - |
다음 유형 중 하나:
|
||||
| name | - | 상수 템플릿 매개변수의 이름 | ||||
| default | - | default template argument |
구조적 타입(structural type)
은 다음 타입 중 하나입니다(선택적으로 cv 한정자를 가질 수 있으며, 한정자는 무시됩니다):
- lvalue 참조 타입 (객체 또는 함수에 대한);
- 정수형 타입 ;
- 포인터 타입 (객체 또는 함수에 대한);
- 멤버 포인터 타입 (멤버 객체 또는 멤버 함수에 대한);
- 열거형 타입 ;
| (C++11 이후) |
|
(C++20부터) |
배열 및 함수 타입은 템플릿 선언에서 작성될 수 있지만, 적절하게 객체에 대한 포인터 및 함수에 대한 포인터로 자동 대체됩니다.
상수 템플릿 매개변수의 이름이 클래스 템플릿 본문 내의 표현식에서 사용될 때, 해당 타입이 lvalue 참조 타입이 아닌 한 수정 불가능한 prvalue 입니다 , 또는 해당 타입이 클래스 타입이 아닌 한 (C++20부터) .
class
Foo
형태의 템플릿 매개변수는
Foo
타입의 이름 없는 상수 템플릿 매개변수가 아닙니다. 설령 다른 상황에서
class
Foo
가
elaborated type specifier
이고
class
Foo x
;
가
x
를
Foo
타입으로 선언한다 하더라도 마찬가지입니다.
|
클래스 타입
struct A { friend bool operator==(const A&, const A&) = default; }; template<A a> void f() { &a; // OK const A& ra = a, &rb = a; // Both bound to the same template parameter object assert(&ra == &rb); // passes } |
(C++20부터) |
타입 템플릿 매개변수
| type-parameter-key name (선택 사항) | (1) | ||||||||
type-parameter-key
name
(선택 사항)
=
default
|
(2) | ||||||||
type-parameter-key
...
name
(선택 사항)
|
(3) | (C++11부터) | |||||||
| type-constraint name (선택 사항) | (4) | (C++20부터) | |||||||
type-constraint
name
(선택 사항)
=
default
|
(5) | (C++20부터) | |||||||
type-constraint
...
name
(선택 사항)
|
(6) | (C++20부터) | |||||||
| type-parameter-key | - |
typename
또는
class
중 하나. 타입 템플릿 매개변수 선언에서 이 두 키워드 간에는 차이가 없음
|
| type-constraint | - | concept 의 이름이거나, 꺾쇠괄호 안에 템플릿 인자 목록이 뒤따르는 concept 이름. 어느 경우든 concept 이름은 선택적으로 한정될 수 있음 |
| name | - | 타입 템플릿 매개변수의 이름 |
| default | - | 기본 템플릿 인자 |
template<class T> class My_vector { /* ... */ };
template<class T = void> struct My_op_functor { /* ... */ };
template<My_concept T> class My_constrained_vector { /* ... */ };
template<My_concept T = void> class My_constrained_op_functor { /* ... */ };
매개변수의 이름은 선택 사항입니다:
// 위에 표시된 템플릿들의 선언: template<class> class My_vector; template<class = void> struct My_op_functor; template<typename...> class My_tuple;
템플릿 선언 본문에서, 타입 매개변수의 이름은 템플릿이 인스턴스화될 때 제공된 타입을 별칭으로 지정하는 typedef-name입니다.
|
각 제약된 매개변수
template<typename T> concept C1 = true; template<typename... Ts> // variadic concept concept C2 = true; template<typename T, typename U> concept C3 = true; template<C1 T> struct s1; // constraint-expression is C1<T> template<C1... T> struct s2; // constraint-expression is (C1<T> && ...) template<C2... T> struct s3; // constraint-expression is (C2<T> && ...) template<C3<int> T> struct s4; // constraint-expression is C3<T, int> template<C3<int>... T> struct s5; // constraint-expression is (C3<T, int> && ...) |
(C++20부터) |
템플릿 템플릿 매개변수
template
<
parameter-list
>
type-parameter-key
name
(선택 사항)
|
(1) | ||||||||
template
<
parameter-list
>
type-parameter-key
name
(선택 사항)
=
default
|
(2) | ||||||||
template
<
parameter-list
>
type-parameter-key
...
name
(선택 사항)
|
(3) | (C++11 이후) | |||||||
| type-parameter-key | - |
class
또는
typename
(C++17부터)
|
템플릿 선언 본문에서 이 매개변수의 이름은 템플릿 이름입니다(그리고 인스턴스화하려면 인수가 필요합니다).
template<typename T> class my_array {}; // 두 개의 타입 템플릿 매개변수와 하나의 템플릿 템플릿 매개변수: template<typename K, typename V, template<typename> typename C = my_array> class Map { C<K> key; C<V> value; };
템플릿 매개변수에 대한 이름 해석
템플릿 매개변수의 이름은 해당 범위(중첩된 범위 포함) 내에서 재선언될 수 없습니다. 템플릿 매개변수는 템플릿 이름과 동일한 이름을 가질 수 없습니다.
template<class T, int N> class Y { int T; // 오류: 템플릿 매개변수 재선언 void f() { char T; // 오류: 템플릿 매개변수 재선언 } }; template<class X> class X; // 오류: 템플릿 매개변수 재선언
클래스 템플릿 정의 외부에 나타나는 클래스 템플릿 멤버의 정의에서, 클래스 템플릿 멤버의 이름은 모든 바깥쪽 클래스 템플릿의 템플릿 매개변수 이름을 가리지만, 해당 멤버가 클래스 또는 함수 템플릿인 경우 멤버의 템플릿 매개변수는 가리지 않습니다.
template<class T> struct A { struct B {}; typedef void C; void f(); template<class U> void g(U); }; template<class B> void A<B>::f() { B b; // A의 B, 템플릿 매개변수가 아님 } template<class B> template<class C> void A<B>::g(C) { B b; // A의 B, 템플릿 매개변수가 아님 C c; // 템플릿 매개변수 C, A의 C가 아님 }
클래스 템플릿 정의를 포함하는 네임스페이스 외부에 나타나는 클래스 템플릿 멤버의 정의에서, 템플릿 매개변수의 이름은 이 네임스페이스 멤버의 이름을 가립니다.
namespace N { class C {}; template<class T> class B { void f(T); }; } template<class C> void N::B<C>::f(C) { C b; // C는 템플릿 매개변수이며, N::C가 아님 }
클래스 템플릿의 정의 내부 또는 템플릿 정의 외부에 나타나는 이러한 템플릿의 멤버 정의에서, 각각의 비의존적(non-dependent) 기본 클래스에 대해, 기본 클래스의 이름이나 기본 클래스 멤버의 이름이 템플릿 매개변수의 이름과 동일할 경우, 기본 클래스 이름이나 멤버 이름이 템플릿 매개변수 이름을 가립니다.
struct A { struct B {}; int C; int Y; }; template<class B, class C> struct X : A { B b; // A의 B C b; // 오류: A의 C는 타입 이름이 아님 };
기본 템플릿 인수
기본 템플릿 인자는 매개변수 목록에서 = 기호 뒤에 지정됩니다. 기본값은 모든 종류의 템플릿 매개변수(타입, 상수, 또는 템플릿)에 대해 지정할 수 있습니다 , 하지만 매개변수 팩에는 지정할 수 없습니다 (since C++11) .
기본 클래스 템플릿의 템플릿 매개변수에 기본값이 지정된 경우 , 기본 변수 템플릿, (C++14부터) 또는 별칭 템플릿에서, 각 후속 템플릿 매개변수는 반드시 기본 인수를 가져야 합니다 , 단 매우 마지막 매개변수는 템플릿 매개변수 팩일 수 있습니다 (C++11부터) . 함수 템플릿에서는 기본값 뒤에 오는 매개변수에 대한 제한이 없으며 , 매개변수 팩 뒤에는 기본값을 가지거나 함수 인수에서 추론될 수 있는 경우에만 더 많은 타입 매개변수가 올 수 있습니다 (C++11부터) .
기본 매개변수는 허용되지 않습니다
- 클래스 템플릿의 멤버에 대한 클래스 외부 정의에서 (이들은 클래스 본문 내 선언에서 제공되어야 합니다). 비템플릿 클래스의 멤버 템플릿 은 클래스 외부 정의에서 기본 매개변수를 사용할 수 있음에 유의하십시오 (참조: GCC 버그 53856 )
- 프렌드 클래스 템플릿 선언에서
|
(C++11 이전) |
|
friend 함수 템플릿 선언에서, 기본 템플릿 인자는 선언이 정의인 경우에만 허용되며, 이 번역 단위에서 이 함수의 다른 선언이 나타나지 않아야 합니다. |
(since C++11) |
선언부에 나타나는 기본 템플릿 인수는 기본 함수 인수와 유사하게 병합됩니다:
template<typename T1, typename T2 = int> class A; template<typename T1 = int, typename T2> class A; // 위 내용은 다음 코드와 동일합니다: template<typename T1 = int, typename T2 = int> class A;
하지만 동일한 매개변수에 대해 같은 스코프 내에서 기본 인수를 두 번 지정할 수 없습니다:
template<typename T = int> class X; template<typename T = int> class X {}; // 오류
상수 템플릿 매개변수에 대한 기본 템플릿 인자를 파싱할 때, 첫 번째 중첩되지 않은 > 는 greater-than 연산자보다는 템플릿 매개변수 목록의 끝으로 간주됩니다:
template<int i = 3 > 4> // 구문 오류 class X { /* ... */ }; template<int i = (3 > 4)> // 정상 class Y { /* ... */ };
템플릿 템플릿 매개변수의 템플릿 매개변수 목록은 자체 기본 인수를 가질 수 있으며, 이는 템플릿 템플릿 매개변수 자체가 스코프 내에 있는 경우에만 유효합니다:
// 기본값을 가진 타입 템플릿 매개변수를 사용하는 클래스 템플릿 template<typename T = float> struct B {}; // 템플릿 템플릿 매개변수 T는 기본값을 가진 하나의 타입 템플릿 매개변수로 구성된 매개변수 목록을 가짐 template<template<typename = float> typename T> struct A { void f(); void g(); }; // 외부 정의 멤버 함수 템플릿 template<template<typename TT> class T> void A<T>::f() { T<> t; // 오류: TT에 스코프 내 기본값이 없음 } template<template<typename TT = char> class T> void A<T>::g() { T<> t; // OK: t는 T<char>임 }
멤버 접근 은 기본 템플릿 매개변수에서 사용된 이름에 대해 선언 시점에 확인되며, 사용 시점에 확인되지 않습니다:
class B {}; template<typename T> class C { protected: typedef T TT; }; template<typename U, typename V = typename U::TT> class D: public U {}; D<C<B>>* d; // 오류: C::TT는 protected 접근 제한을 가짐
|
기본 템플릿 인자는 해당 기본 인자의 값이 필요할 때 암시적으로 인스턴스화됩니다. 단, 템플릿이 함수의 이름을 지정하는 데 사용되는 경우는 예외입니다: template<typename T, typename U = int> struct S {}; S<bool>* p; // U에 대한 기본 인자가 이 시점에서 인스턴스화됨 // p의 타입은 S<bool, int>* |
(C++14부터) |
참고 사항
C++26 이전에는, 상수 템플릿 매개변수가 표준 용어에서 비타입 템플릿 매개변수(non-type template parameter)로 불렸습니다. 이 용어는 P2841R6 / PR#7587 에 의해 변경되었습니다.
|
템플릿 매개변수에서 타입 제약은 auto 의 존재 여부에 따라 타입 매개변수와 상수 매개변수 모두에 사용될 수 있습니다. template<typename> concept C = true; template<C, // type parameter C auto // constant parameter > struct S{}; S<int, 0> s;
|
(since C++20) |
| 기능 테스트 매크로 | 값 | 표준 | 기능 |
|---|---|---|---|
__cpp_nontype_template_parameter_auto
|
201606L
|
(C++17) | 상수 템플릿 매개변수 를 auto 로 선언 |
__cpp_nontype_template_args
|
201411L
|
(C++17) | 모든 상수 템플릿 인수 에 대해 상수 평가 허용 |
201911L
|
(C++20) | 상수 템플릿 매개변수 에서 클래스 타입과 부동소수점 타입 허용 |
예제
#include <array> #include <iostream> #include <numeric> // 단순한 상수 템플릿 매개변수 template<int N> struct S { int a[N]; }; template<const char*> struct S2 {}; // 복잡한 상수 예제 template < char c, // 정수형 int (&ra)[5], // 객체에 대한 좌측값 참조 (배열 타입) int (*pf)(int), // 함수 포인터 int (S<10>::*a)[10] // 멤버 객체 포인터 (int[10] 타입) > struct Complicated { // 컴파일 타임에 선택된 함수를 호출하고 // 컴파일 타임에 선택된 배열에 결과를 저장 void foo(char base) { ra[4] = pf(c - base); } }; // S2<"fail"> s2; // 오류: 문자열 리터럴은 사용할 수 없음 char okay[] = "okay"; // 링크를 가진 정적 객체 // S2<&okay[0]> s3; // 오류: 배열 요소는 링크를 가지지 않음 S2<okay> s4; // 작동함 int a[5]; int f(int n) { return n; } // C++20: NTTP는 리터럴 클래스 타입일 수 있음 template<std::array arr> constexpr auto sum() { return std::accumulate(arr.cbegin(), arr.cend(), 0); } // C++20: 클래스 템플릿 인자는 호출 지점에서 추론됨 static_assert(sum<std::array<double, 8>{3, 1, 4, 1, 5, 9, 2, 6}>() == 31.0); // C++20: NTTP 인자 추론과 CTAD static_assert(sum<std::array{2, 7, 1, 8, 2, 8}>() == 28); int main() { S<10> s; // s.a는 10개의 int 배열 s.a[9] = 4; Complicated<'2', a, f, &S<10>::a> c; c.foo('0'); std::cout << s.a[9] << a[4] << '\n'; }
출력:
42
|
이 섹션은 불완전합니다
이유: 더 많은 예시 필요 |
결함 보고서
다음의 동작 변경 결함 보고서들은 이전에 발표된 C++ 표준에 소급 적용되었습니다.
| DR | 적용 대상 | 게시된 동작 | 올바른 동작 |
|---|---|---|---|
| CWG 184 | C++98 |
템플릿 템플릿 매개변수의 템플릿 매개변수가
기본 인수를 가질 수 있는지 여부가 명시되지 않음 |
명세 추가됨 |
| CWG 1922 | C++98 |
이름이 injected-class-name인 클래스 템플릿이 이전 선언의
기본 인수를 사용할 수 있는지 불명확했음 |
허용됨 |
| CWG 2032 | C++14 |
변수 템플릿의 경우 기본 인수가 있는 템플릿 매개변수 이후의
템플릿 매개변수에 대한 제한이 없었음 |
클래스 템플릿 및
별칭 템플릿과 동일한 제한 적용 |
| CWG 2542 | C++20 | 클로저 타입이 structural인지 불명확했음 | structural이 아님 |
| CWG 2845 | C++20 | 클로저 타입이 structural이 아니었음 |
캡처가 없는 경우
structural임 |