Namespaces
Variants

Template arguments

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

템플릿이 인스턴스화되기 위해서는 모든 템플릿 매개변수 가 해당 템플릿 인수로 대체되어야 합니다. 인수는 명시적으로 제공되거나, 추론되거나, 기본값이 사용됩니다.

template-parameter-list ( template identifier syntax 참조)의 각 매개변수는 다음 범주 중 하나에 속합니다:

  • 상수 템플릿 인수
  • 타입 템플릿 인수
  • 템플릿 템플릿 인수

목차

상수 템플릿 인수

비타입 템플릿 인자 로도 알려져 있습니다 (자세한 내용은 아래 참조).

상수 템플릿 매개변수와 함께 사용할 수 있는 템플릿 인자는 모든 manifestly constant-evaluated expression 이 될 수 있습니다.

(until C++11)

상수 템플릿 매개변수와 함께 사용할 수 있는 템플릿 인자는 모든 initializer clause 가 될 수 있습니다. 초기화 절이 표현식인 경우, 반드시 manifestly constant-evaluated 되어야 합니다.

(since C++11)

주어진 type 상수 템플릿 매개변수 선언 T 로 하고, 이 매개변수에 제공된 템플릿 인자를 E 로 합니다.

발명된 선언 T x = E ; constexpr 변수 의 정의를 위한 의미론적 제약 조건을 정적 저장 기간 으로 만족해야 합니다.

(C++20부터)

만약 T 플레이스홀더 타입 을 포함하거나 추론된 클래스 타입에 대한 플레이스홀더 인 경우, 템플릿 매개변수의 타입은 발명된 선언 T x = E ; 에서 변수 x 에 대해 추론된 타입입니다.

추론된 매개변수 타입이 구조적 타입 이 아닌 경우, 프로그램은 ill-formed입니다.

플레이스홀더 타입을 사용하는 타입을 가진 상수 템플릿 매개변수 팩의 경우, 타입은 각 템플릿 인수에 대해 독립적으로 추론되며 일치할 필요가 없습니다.

(C++17부터)
template<auto n>
struct B { /* ... */ };
B<5> b1;   // OK: 상수 템플릿 매개변수 타입은 int
B<'a'> b2; // OK: 상수 템플릿 매개변수 타입은 char
B<2.5> b3; // 오류 (C++20 이전): 상수 템플릿 매개변수 타입은 double이 될 수 없음
// C++20에서 추론된 클래스 타입 플레이스홀더, 클래스 템플릿 인자는
// 호출 지점에서 추론됨
template<std::array arr>
void f();
f<std::array<double, 8>{}>();
template<auto...>
struct C {};
C<'C', 0, 2L, nullptr> x; // OK

상수 템플릿 매개변수 P 의 값은 (추론된 가능성이 있는) (C++17부터) 타입 T 로부터 다음과 같이 템플릿 인수 A 에 의해 결정됩니다:

  • 만약 A T 타입의 변환된 상수 표현식 이라면, P 의 값은 (변환된 형태로) A 입니다.
  • 그렇지 않으면, 프로그램의 형식이 올바르지 않습니다.
(C++11 이전)
  • 만약 A 가 표현식이라면:
  • 만약 A T 타입의 변환된 상수 표현식 이라면, P 의 값은 (변환된 형태로) A 입니다.
  • 그렇지 않으면, 프로그램의 형식이 올바르지 않습니다.
  • 그렇지 않은 경우 ( A 가 중괄호로 둘러싸인 초기화 리스트), 임시 변수 constexpr T v = A ; 가 도입됩니다. P 의 값은 v 의 값입니다.
  • v 수명 은 이를 초기화한 직후에 종료됩니다.
(C++11 이후)
(C++20 이전)
  • 만약 T 가 클래스 타입이 아니고 A 가 표현식이라면:
  • 만약 A T 타입의 변환된 상수 표현식 이라면, P 의 값은 (변환된 형태로) A 입니다.
  • 그렇지 않으면, 프로그램의 형식이 올바르지 않습니다.
  • 그렇지 않은 경우 ( T 가 클래스 타입이거나 A 가 중괄호로 둘러싸인 초기화 리스트), 임시 변수 constexpr T v = A ; 가 도입됩니다.
  • v P 를 초기화한 직후 v 수명 이 종료됩니다.
  • 다음 조건 중 하나를 P 의 초기화가 만족한다면, 프로그램의 형식이 올바르지 않습니다:
  • 그렇지 않으면, P 의 값은 v 의 값입니다.
(C++20 이후)
template<int i>
struct C { /* ... */ };
C<{42}> c1; // 정상
template<auto n>
struct B { /* ... */ };
struct J1
{
    J1* self = this;
};
B<J1{}> j1; // 오류: 템플릿 매개변수 객체의 초기화가
            //        상수 표현식이 아님
struct J2
{
    J2 *self = this;
    constexpr J2() {}
    constexpr J2(const J2&) {}
};
B<J2{}> j2; // 오류: 템플릿 매개변수 객체가
            //        도입된 임시 객체와 템플릿 인자 동등하지 않음

상수 템플릿 매개변수를 가진 템플릿을 인스턴스화할 때 다음과 같은 제한 사항이 적용됩니다:

  • 정수 및 산술 타입의 경우, 인스턴스화 시 제공되는 템플릿 인자는 템플릿 매개변수 타입의 변환된 상수 표현식 이어야 합니다(특정 암시적 변환이 적용됨).
  • 객체 포인터의 경우, 템플릿 인자는 정적 저장 기간 링크 (내부 또는 외부)을 가진 완전한 객체의 주소이거나, 적절한 널 포인터 값으로 평가되는 상수 표현식이어야 합니다 또는 std::nullptr_t (since C++11) .
  • 함수 포인터의 경우, 유효한 인자는 링크를 가진 함수에 대한 포인터(또는 널 포인터 값으로 평가되는 상수 표현식)입니다.
  • lvalue 참조 매개변수의 경우, 인스턴스화 시 제공되는 인자는 임시 객체, 이름 없는 lvalue, 또는 링크가 없는 이름 있는 lvalue일 수 없습니다(즉, 인자는 링크를 가져야 합니다).
  • 멤버 포인터의 경우, 인자는 & Class :: Member 로 표현된 멤버 포인터이거나 널 포인터 값으로 평가되는 상수 표현식이어야 합니다 또는 std::nullptr_t (since C++11) .

특히, 이는 문자열 리터럴, 배열 요소의 주소, 비정적 멤버의 주소가 객체 포인터인 해당 상수 템플릿 매개변수를 가진 템플릿을 인스턴스화하는 데 템플릿 인자로 사용될 수 없음을 의미합니다.

(until C++17)

참조 또는 포인터 타입의 상수 템플릿 매개변수 및 클래스 타입의 상수 템플릿 매개변수와 그 하위 객체에서 참조 또는 포인터 타입의 비정적 데이터 멤버 (since C++20) 는 다음을 참조하거나 그 주소일 수 없습니다:

  • 임시 객체( 참조 초기화 중 생성된 객체 포함);
  • 문자열 리터럴 ;
  • typeid 의 결과;
  • 미리 정의된 변수 __func__ ;
  • 또는 위 항목들의 하위 객체(비정적 클래스 멤버, 기본 클래스 하위 객체, 배열 요소 포함) 중 하나 (since C++20) .
(since C++17)
template<const int* pci>
struct X {};
int ai[10];
X<ai> xi; // OK: 배열에서 포인터로의 변환 및 cv-한정자 변환
struct Y {};
template<const Y& b>
struct Z {};
Y y;
Z<y> z;   // OK: 변환 없음
template<int (&pa)[5]>
struct W {};
int b[5];
W<b> w;   // OK: 변환 없음
void f(char);
void f(int);
template<void (* pf)(int)>
struct A {};
A<&f> a;  // OK: 오버로드 해결이 f(int)를 선택함
template<class T, const char* p>
class X {};
X<int, "Studebaker"> x1; // 오류: 템플릿 인자로 문자열 리터럴 사용
template<int* p>
class X {};
int a[10];
struct S
{
    int m;
    static int s;
} s;
X<&a[2]> x3; // 오류 (C++20 이전): 배열 요소의 주소
X<&s.m> x4;  // 오류 (C++20 이전): 비정적 멤버의 주소
X<&s.s> x5;  // 정상: 정적 멤버의 주소
X<&S::s> x6; // 정상: 정적 멤버의 주소
template<const int& CRI>
struct B {};
B<1> b2;     // 오류: 템플릿 인자에 임시 객체가 필요함
int c = 1;
B<c> b1;     // 정상

타입 템플릿 인수

타입 템플릿 매개변수에 대한 템플릿 인수는 type-id 여야 하며, 이는 불완전한 타입을 명시할 수 있습니다:

template<typename T>
class X {}; // 클래스 템플릿
struct A;            // 불완전 타입
typedef struct {} B; // 이름 없는 타입에 대한 타입 별칭
int main()
{
    X<A> x1;  // OK: 'A'는 타입을 나타냄
    X<A*> x2; // OK: 'A*'는 타입을 나타냄
    X<B> x3;  // OK: 'B'는 타입을 나타냄
}

템플릿 템플릿 인수

템플릿 템플릿 매개변수에 대한 템플릿 인자는 반드시 id-expression 이어야 하며, 이는 클래스 템플릿이나 템플릿 별칭을 지정해야 합니다.

인자가 클래스 템플릿인 경우, 매개변수와 매칭할 때는 기본 템플릿만 고려됩니다. 부분 특수화가 존재하는 경우, 이 템플릿 템플릿 매개변수를 기반으로 한 특수화가 실제로 인스턴스화될 때만 고려됩니다.

template<typename T> // 기본 템플릿
class A { int x; };
template<typename T> // 부분 특수화
class A<T*> { long x; };
// 템플릿 템플릿 매개변수 V를 가진 클래스 템플릿
template<template<typename> class V>
class C
{
    V<int> y;  // 기본 템플릿 사용
    V<int*> z; // 부분 특수화 사용
};
C<A> c; // c.y.x는 int 타입, c.z.x는 long 타입

템플릿 템플릿 인수 A 를 템플릿 템플릿 매개변수 P 와 매칭시키기 위해서는, P A 보다 최소한 동등하게 특수화되어야 합니다 (아래 참조). P 의 매개변수 목록에 파라미터 팩 이 포함된 경우, A 의 템플릿 매개변수 목록에서 0개 이상의 템플릿 매개변수(또는 파라미터 팩)가 이와 매칭됩니다. (C++11부터)

공식적으로, 템플릿 템플릿 매개변수 P 는 다음과 같은 두 함수 템플릿으로 재작성할 때, 함수 템플릿 에 대한 부분 순서 규칙에 따라 P 에 해당하는 함수 템플릿이 A 에 해당하는 함수 템플릿보다 최소한 동등하게 특수화되었거나 더 특수화된 경우 , 템플릿 템플릿 인수 A 보다 최소한 동등하게 특수화되었거나 더 특수화된 것으로 간주합니다. A 의 템플릿 매개변수 목록(기본 인수 포함)을 가진 가상의 클래스 템플릿 X 가 주어졌을 때:

  • 두 함수 템플릿은 각각 P 또는 A 와 동일한 템플릿 매개변수를 가집니다.
  • 각 함수 템플릿은 해당 함수 템플릿의 템플릿 매개변수에 대응하는 템플릿 인자로 특수화된 X 타입의 단일 함수 매개변수를 가지며, 여기서 함수 템플릿의 템플릿 매개변수 목록에 있는 각 템플릿 매개변수 PP 에 대해 대응하는 템플릿 인자 AA 가 형성됩니다. 만약 PP 가 매개변수 팩을 선언한다면, AA 는 팩 확장 PP... 입니다; 그렇지 않으면, (C++11부터) AA 는 id-표현식 PP 입니다.

만약 재작성 결과가 유효하지 않은 타입을 생성한다면, P A 만큼 특수화되지 않은 것입니다.

template<typename T>
struct eval;                     // 기본 템플릿
template<template<typename, typename...> class TT, typename T1, typename... Rest>
struct eval<TT<T1, Rest...>> {}; // eval의 부분 특수화
template<typename T1> struct A;
template<typename T1, typename T2> struct B;
template<int N> struct C;
template<typename T1, int N> struct D;
template<typename T1, typename T2, int N = 17> struct E;
eval<A<int>> eA;        // OK: eval의 부분 특수화와 일치
eval<B<int, float>> eB; // OK: eval의 부분 특수화와 일치
eval<C<17>> eC;         // 오류: C가 부분 특수화의 TT와 일치하지 않음
                        // TT의 첫 번째 매개변수는 타입 템플릿 매개변수인 반면
                        // 17은 타입을 명시하지 않음
eval<D<int, 17>> eD;    // 오류: D가 부분 특수화의 TT와 일치하지 않음
                        // TT의 두 번째 매개변수는 타입 매개변수 팩인 반면
                        // 17은 타입을 명시하지 않음
eval<E<int, float>> eE; // 오류: E가 부분 특수화의 TT와 일치하지 않음
                        // E의 세 번째(기본) 매개변수는 상수임

P0522R0 가 채택되기 전에는, A 의 각 템플릿 매개변수가 P 의 해당 템플릿 매개변수와 정확히 일치해야 했습니다. 이로 인해 많은 합리적인 템플릿 인수가 수용되지 못하는 문제가 있었습니다.

이 문제는 매우 일찍 지적되었지만( CWG#150 ), 해결될 때쯤에는 변경 사항들이 C++17 작업 문서에 적용되어 해당 해결책이 사실상 C++17 기능이 되었습니다. 많은 컴파일러들이 기본적으로 이를 비활성화합니다:

  • GCC 는 C++17 이전의 모든 언어 모드에서 기본적으로 이를 비활성화하며, 이러한 모드에서는 컴파일러 플래그를 설정해야만 활성화할 수 있습니다.
  • Clang 는 모든 언어 모드에서 기본적으로 이를 비활성화하며, 컴파일러 플래그를 설정해야만 활성화할 수 있습니다.
  • Microsoft Visual Studio 는 이를 일반적인 C++17 기능으로 취급하며 C++17 이상의 언어 모드에서만 활성화합니다(즉, 기본 모드인 C++14 언어 모드에서는 지원되지 않음).
template<class T> class A { /* ... */ };
template<class T, class U = T> class B { /* ... */ };
template<class... Types> class C { /* ... */ };
template<template<class> class P> class X { /* ... */ };
X<A> xa; // 정상
X<B> xb; // P0522R0 이후 정상
         // 이전에는 오류: 정확히 일치하지 않음
X<C> xc; // P0522R0 이후 정상
         // 이전에는 오류: 정확히 일치하지 않음
template<template<class...> class Q> class Y { /* ... */ };
Y<A> ya; // 정상
Y<B> yb; // 정상
Y<C> yc; // 정상
template<auto n> class D { /* ... */ };   // 참고: C++17
template<template<int> class R> class Z { /* ... */ };
Z<D> zd; // P0522R0 이후 정상: 템플릿 매개변수가
         // 템플릿 인수보다 더 특수화됨
template<int> struct SI { /* ... */ };
template<template<auto> class> void FA(); // 참고: C++17
FA<SI>(); // 오류

템플릿 인자 동등성

템플릿 인자 동등성은 두 개의 템플릿 식별자 가 동일한지 결정하는 데 사용됩니다.

두 값은 동일한 타입이고 다음 조건 중 하나를 만족하는 경우 template-argument-equivalent 입니다:

  • 정수형이나 열거형이며 그 값이 동일한 경우
  • 포인터 타입이며 동일한 포인터 값을 가지는 경우
  • 멤버 포인터 타입이며 동일한 클래스 멤버를 참조하거나 둘 다 null 멤버 포인터 값인 경우
  • lvalue 참조 타입이며 동일한 객체나 함수를 참조하는 경우
(C++11부터)
  • 부동 소수점 타입이며 그 값이 동일한 경우
  • 배열 타입인 경우 (이때 배열들은 어떤 클래스/공용체의 멤버 객체여야 함) 그리고 해당 배열 요소들이 템플릿 인자 동등한 경우
  • 공용체 타입이며 둘 다 활성 멤버가 없거나 동일한 활성 멤버를 가지며 그 활성 멤버들이 템플릿 인자 동등한 경우
  • 람다 클로저 타입인 경우
  • 비공용체 클래스 타입이며 해당 직접 하위 객체들과 참조 멤버들이 템플릿 인자 동등한 경우
(C++20부터)

모호성 해결

템플릿 인자가 type-id 와 표현식(expression) 모두로 해석될 수 있는 경우, 해당 템플릿 매개변수가 상수(constant)라 하더라도 항상 type-id로 해석됩니다:

template<class T>
void f(); // #1
template<int I>
void f(); // #2
void g()
{
    f<int()>(); // "int()"는 타입이면서 표현식입니다,
                // 타입으로 해석되므로 #1을 호출합니다
}

참고 사항

C++26 이전에는, 상수 템플릿 인수가 표준 용어에서 비타입 템플릿 인수라고 불렸습니다. 이 용어는 P2841R6 / PR #7587 에 의해 변경되었습니다.

기능 테스트 매크로 표준 기능
__cpp_template_template_args 201611L (C++17)
(DR)
템플릿 템플릿 인자 의 매칭
__cpp_nontype_template_args 201411L (C++17) 모든 상수 템플릿 인자 에 대한 상수 평가 허용
201911L (C++20) 상수 템플릿 매개변수 에서의 클래스 타입과 부동소수점 타입

예제

결함 보고서

다음의 동작 변경 결함 보고서들은 이전에 발표된 C++ 표준에 소급 적용되었습니다.

DR 적용 대상 게시된 동작 올바른 동작
CWG 150
( P0522R0 )
C++98 템플릿-템플릿 인수가 템플릿-템플릿 매개변수의
매개변수 목록과 정확히 일치해야 했음
더 특수화된 경우도
허용됨
CWG 354 C++98 널 포인터 값을 상수 템플릿 인수로 사용할 수 없었음 허용됨
CWG 1398 C++11 상수 템플릿 인수가 std::nullptr_t 타입을 가질 수 없었음 허용됨
CWG 1570 C++98 상수 템플릿 인수가 하위 객체의 주소를 지정할 수 있었음 허용되지 않음
P2308R1 C++11
C++20
1. 상수 템플릿 인수에 대해 목록 초기화가
허용되지 않았음 (C++11)
2. 클래스 타입의 상수 템플릿 매개변수가 어떻게
초기화되는지 불분명했음 (C++20)
1. 허용됨
2. 명확히 규정됨