名前空間
変種
操作

テンプレートパラメータとテンプレート引数

From cppreference.com
< cpp‎ | language
 
 
C++言語
全般
フロー制御
条件実行文
if
繰り返し文 (ループ)
for
範囲for (C++11)
ジャンプ文
関数
関数宣言
ラムダ式
inline指定子
動的例外仕様 (C++17まで*)
noexcept指定子 (C++11)
例外
名前空間
指定子
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
記憶域期間指定子
初期化
代替表現
リテラル
ブーリアン - 整数 - 浮動小数点数
文字 - 文字列 - nullptr (C++11)
ユーザー定義 (C++11)
ユーティリティ
属性 (C++11)
typedef宣言
型エイリアス宣言 (C++11)
キャスト
メモリ確保
クラス
クラス固有の関数プロパティ
explicit (C++11)
static

特殊メンバ関数
テンプレート
その他
 
 
 
 

目次

[edit] テンプレートパラメータ

すべてのテンプレートは、テンプレート宣言構文のparameter-listで示される1つ以上のテンプレートパラメータによってパラメータ化されます。

template < parameter-list > declaration (1)
template < parameter-list > requires constraint declaration (2) (C++20以降)

parameter-list の各パラメータは、次のいずれかです。

  • 非型テンプレートパラメータ;
  • 型テンプレートパラメータ;
  • テンプレートテンプレートパラメータ。


[edit] 非型テンプレートパラメータ

type name(オプション) (1)
type name(オプション) = default (2)
type ... name(オプション) (3) (C++11以降)
1) 非型テンプレートパラメータ。
2) デフォルトテンプレート引数を持つ非型テンプレートパラメータ。
3) 非型テンプレートパラメータパック
type - 次の型のいずれか
  • 構造型 (下記参照)
(C++17以降)
(C++20以降)
name - 非型テンプレートパラメータの名前
default - デフォルトテンプレート引数

構造型とは、次の型のいずれかです (オプションで cv 修飾されますが、修飾子は無視されます)。

(C++11以降)
  • すべての基底クラスおよび非静的データメンバは public かつ非可変であり、
  • すべての基底クラスおよび非静的データメンバの型は構造型であるか、それらの (多次元の可能性のある) 配列である。
(C++20以降)

配列型と関数型はテンプレート宣言で記述できますが、それぞれ適切なオブジェクトへのポインタと関数へのポインタに自動的に置き換えられます。

クラステンプレートの本体内で非型テンプレートパラメータの名前が式で使用される場合、その型が左辺値参照型でない限り、変更不可能なprvalueです、またはその型がクラス型である場合を除いて(C++20以降)

形式 class Foo のテンプレートパラメータは、たとえ class Fooelaborated type specifierであり、class Foo x;x を型 Foo のものと宣言していても、型 Foo の無名の非型テンプレートパラメータではありません。

クラス型 T の非型テンプレートパラメータを命名する識別子は、テンプレートパラメータオブジェクトと呼ばれる型 const T の静的記憶域期間オブジェクトを表します。これは、テンプレートパラメータの型に変換された後、対応するテンプレート引数とテンプレート引数等価です。2つのテンプレートパラメータオブジェクトがテンプレート引数等価になることはありません。

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以降)

[edit] 型テンプレートパラメータ

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 - コンセプトの名前、またはコンセプトの名前の後にテンプレート引数リスト (山括弧内) が続くもの。どちらの場合も、コンセプト名はオプションで修飾できます。
name - 型テンプレートパラメータの名前
default - デフォルトテンプレート引数
1) デフォルトのない型テンプレートパラメータ。
template<class T>
class My_vector { /* ... */ };
2) デフォルトのある型テンプレートパラメータ。
template<class T = void>
struct My_op_functor { /* ... */ };
3) 型テンプレートパラメータパック
template<typename... Ts>
class My_tuple { /* ... */ };
4) デフォルトのない制約付き型テンプレートパラメータ。
template<My_concept T>
class My_constrained_vector { /* ... */ };
5) デフォルトのある制約付き型テンプレートパラメータ。
template<My_concept T = void>
class My_constrained_op_functor { /* ... */ };
6) 制約付き型テンプレートパラメータパック
template<My_concept... Ts>
class My_constrained_tuple { /* ... */ };

パラメータの名前はオプションです。

// Declarations of the templates shown above:
template<class>
class My_vector;
template<class = void>
struct My_op_functor;
template<typename...>
class My_tuple;

テンプレート宣言の本体では、型パラメータの名前は、テンプレートがインスタンス化されるときに提供される型の別名となる typedef-name です。

コンセプト C を指定するtype-constraint Q を持つ各制約付きパラメータ P は、次の規則に従って制約式 E を導入します。

  • QC (引数リストなし) の場合、
  • P がパラメータパックでない場合、E は単純に C<P> です。
  • それ以外の場合、P はパラメータパックであり、E はフォールド式 (C<P> && ...) です。
  • QC<A1,A2...,AN> の場合、E はそれぞれ C<P,A1,A2,...AN> または (C<P,A1,A2,...AN> && ...) です。
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以降)

[edit] テンプレートテンプレートパラメータ

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以降)
1) オプションの名前を持つテンプレートテンプレートパラメータ。
2) オプションの名前とデフォルトを持つテンプレートテンプレートパラメータ。
3) オプションの名前を持つテンプレートテンプレートパラメータパック

テンプレート宣言の本体では、このパラメータの名前はテンプレート名です (インスタンス化には引数が必要です)。

template<typename T>
class my_array {};
 
// two type template parameters and one template template parameter:
template<typename K, typename V, template<typename> typename C = my_array>
class Map
{
    C<K> key;
    C<V> value;
};

[edit] テンプレートパラメータの名前解決

テンプレートパラメータの名前は、そのスコープ内 (ネストされたスコープを含む) で再宣言することはできません。テンプレートパラメータはテンプレート名と同じ名前を持つことはできません。

template<class T, int N>
class Y
{
    int T;      // error: template parameter redeclared
    void f()
    {
        char T; // error: template parameter redeclared
    }
};
 
template<class X>
class X; // error: template parameter redeclared

クラステンプレートの定義の外側に現れるクラステンプレートのメンバの定義では、クラステンプレートのメンバの名前は、囲んでいるクラステンプレートのテンプレートパラメータの名前を隠しますが、そのメンバがクラスまたは関数テンプレートである場合、そのメンバのテンプレートパラメータの名前は隠しません。

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's B, not the template parameter
}
 
template<class B>
template<class C>
void A<B>::g(C)
{
    B b; // A's B, not the template parameter
    C c; // the template parameter C, not A's 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 is the template parameter, not N::C
}

クラステンプレートの定義、またはテンプレート定義の外側に現れるそのようなテンプレートのメンバの定義では、非依存基底クラスごとに、基底クラスの名前または基底クラスのメンバの名前がテンプレートパラメータの名前と同じ場合、基底クラスの名前またはメンバの名前はテンプレートパラメータの名前を隠します。

struct A
{
    struct B {};
    int C;
    int Y;
};
 
template<class B, class C>
struct X : A
{
    B b; // A's B
    C b; // error: A's C isn't a type name
};

[edit] テンプレート引数

テンプレートをインスタンス化するには、すべてのテンプレートパラメータ (型、非型、またはテンプレート) を対応するテンプレート引数に置き換える必要があります。クラステンプレートの場合、引数は明示的に提供されるかイニシャライザから推論されるか(C++17以降) またはデフォルト値が使用されます。関数テンプレートの場合、引数は明示的に提供されるか、コンテキストから推論されるか、またはデフォルト値が使用されます。

引数が型IDと式の両方として解釈できる場合、対応するテンプレートパラメータが非型であっても、常に型IDとして解釈されます。

template<class T>
void f(); // #1
 
template<int I>
void f(); // #2
 
void g()
{
    f<int()>(); // "int()" is both a type and an expression,
                // calls #1 because it is interpreted as a type
}

[edit] 非型テンプレート引数

非型テンプレートパラメータで使用できるテンプレート引数は、あらゆる明らかに定数評価される式です。

(C++11まで)

非型テンプレートパラメータで使用できるテンプレート引数は、あらゆるイニシャライザ句です。イニシャライザ句が式の場合、それは明らかに定数評価されなければなりません。

(C++11以降)

非型テンプレートパラメータ宣言T とし、パラメータに提供されるテンプレート引数を E とします。

考案された宣言 T x = E; は、静的記憶域期間を持つconstexpr 変数の定義に対するセマンティック制約を満たす必要があります。

(C++26以降)

Tプレースホルダ型を含む場合、または推論されたクラス型のプレースホルダである場合、テンプレートパラメータの型は、考案された宣言 T x = E; の変数 x について推論された型です。

推論されたパラメータ型が構造型でない場合、プログラムは不正です。

プレースホルダ型を使用する非型テンプレートパラメータパックの場合、型は各テンプレート引数に対して独立して推論され、一致する必要はありません。

(C++17以降)
template<auto n>
struct B { /* ... */ };
 
B<5> b1;   // OK: non-type template parameter type is int
B<'a'> b2; // OK: non-type template parameter type is char
B<2.5> b3; // error (until C++20): non-type template parameter type cannot be double
 
// C++20 deduced class type placeholder, class template arguments are deduced at the
// call site
template<std::array arr>
void f();
 
f<std::array<double, 8>{}>();
 
template<auto...>
struct C {};
 
C<'C', 0, 2L, nullptr> x; // OK

(推論される可能性のある)(C++17以降)T の非型テンプレートパラメータ P の値は、そのテンプレート引数 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; が導入されます。
  • vP寿命は、初期化直後に終了します。
  • P の初期化が次のいずれかの条件を満たす場合、プログラムは不正です。
  • それ以外の場合、P の値は v の値です。
(C++20以降)
template<int i>
struct C { /* ... */ };
 
C<{42}> c1; // OK
 
template<auto n>
struct B { /* ... */ };
 
struct J1
{
    J1* self = this;
};
 
B<J1{}> j1; // error: initialization of the template parameter object
            //        is not a constant expression
 
struct J2
{
    J2 *self = this;
    constexpr J2() {}
    constexpr J2(const J2&) {}
};
 
B<J2{}> j2; // error: the template parameter object is not
            //        template-argument-equivalent to introduced temporary

非型テンプレートパラメータを持つテンプレートをインスタンス化する場合、以下の制限が適用されます。

  • 整数型と算術型の場合、インスタンス化中に提供されるテンプレート引数は、テンプレートパラメータの型に変換された定数式でなければなりません (したがって、特定の暗黙の変換が適用されます)。
  • オブジェクトへのポインタの場合、テンプレート引数は、静的記憶域期間リンケージ (内部または外部のいずれか) を持つ完全なオブジェクトのアドレス、または適切なヌルポインタまたはstd::nullptr_t(C++11以降)値に評価される定数式を指定する必要があります。
  • 関数へのポインタの場合、有効な引数はリンケージを持つ関数へのポインタ (またはヌルポインタ値に評価される定数式) です。
  • 左辺値参照パラメータの場合、インスタンス化時に提供される引数は、一時オブジェクト、無名の左辺値、またはリンケージを持たない名前付き左辺値であってはなりません (つまり、引数にはリンケージが必要です)。
  • メンバへのポインタの場合、引数は &Class::Member として表現されたメンバへのポインタ、またはヌルポインタまたはstd::nullptr_t(C++11以降)値に評価される定数式でなければなりません。

特に、これは、文字列リテラル、配列要素のアドレス、および非静的メンバのアドレスは、対応する非型テンプレートパラメータがオブジェクトへのポインタであるテンプレートをインスタンス化するためのテンプレート引数として使用できないことを意味します。

(C++17まで)

参照型またはポインタ型の非型テンプレートパラメータ、およびクラス型の非型テンプレートパラメータとそのサブオブジェクト内の参照型またはポインタ型の非静的データメンバ(C++20以降)は、以下を参照したり、以下のアドレスであってはなりません。

  • 一時オブジェクト (参照初期化中に作成されたものを含む);
  • 文字列リテラル;
  • typeid の結果;
  • 定義済みの変数 __func__;
  • または、上記のいずれかのサブオブジェクト (非静的クラスメンバ、基底サブオブジェクト、または配列要素を含む)のサブオブジェクト(C++20以降)
(C++17以降)
template<const int* pci>
struct X {};
 
int ai[10];
X<ai> xi; // OK: array to pointer conversion and cv-qualification conversion
 
struct Y {};
 
template<const Y& b>
struct Z {};
 
Y y;
Z<y> z;   // OK: no conversion
 
template<int (&pa)[5]>
struct W {};
 
int b[5];
W<b> w;   // OK: no conversion
 
void f(char);
void f(int);
 
template<void (*pf)(int)>
struct A {};
 
A<&f> a;  // OK: overload resolution selects f(int)
template<class T, const char* p>
class X {};
 
X<int, "Studebaker"> x1; // error: string literal as template-argument
 
template<int* p>
class X {};
 
int a[10];
 
struct S
{
    int m;
    static int s;
} s;
 
X<&a[2]> x3; // error (until C++20): address of array element
X<&s.m> x4;  // error (until C++20): address of non-static member
X<&s.s> x5;  // OK: address of static member
X<&S::s> x6; // OK: address of static member
 
template<const int& CRI>
struct B {};
 
B<1> b2;     // error: temporary would be required for template argument
int c = 1;
B<c> b1;     // OK

[edit] 型テンプレート引数

型テンプレートパラメータのテンプレート引数は、不完全型を命名できる型IDでなければなりません。

template<typename T>
class X {}; // class template
 
struct A;            // incomplete type
typedef struct {} B; // type alias to an unnamed type
 
int main()
{
    X<A> x1;  // OK: 'A' names a type
    X<A*> x2; // OK: 'A*' names a type
    X<B> x3;  // OK: 'B' names a type
}

[edit] テンプレートテンプレート引数

テンプレートテンプレートパラメータのテンプレート引数は、クラステンプレートまたはテンプレートエイリアスを命名するid-expressionでなければなりません。

引数がクラステンプレートである場合、パラメータとのマッチングにはプライマリテンプレートのみが考慮されます。部分特殊化がある場合、このテンプレートテンプレートパラメータに基づく特殊化がインスタンス化されるときにのみ考慮されます。

template<typename T> // primary template
class A { int x; };
 
template<typename T> // partial specialization
class A<T*> { long x; };
 
// class template with a template template parameter V
template<template<typename> class V>
class C
{
    V<int> y;  // uses the primary template
    V<int*> z; // uses the partial specialization
};
 
C<A> c; // c.y.x has type int, c.z.x has type long

テンプレートテンプレート引数 A をテンプレートテンプレートパラメータ P にマッチさせるには、PA よりも少なくとも特殊化されている必要があります (下記参照)P のパラメータリストにパラメータパックが含まれている場合、A のテンプレートパラメータリストから0個以上のテンプレートパラメータ (またはパラメータパック) がそれによってマッチされます。(C++11以降)

形式的には、テンプレートテンプレートパラメータ P がテンプレートテンプレート引数 A よりも少なくとも特殊化されているのは、2つの関数テンプレートに対する次の書き換えが与えられたとき、P に対応する関数テンプレートが関数テンプレートの部分順序付け規則に従って A に対応する関数テンプレートよりも少なくとも特殊化されている場合です。テンプレートパラメータリストが A のものと同じである (デフォルト引数を含む) 考案されたクラステンプレート X が与えられたとき、

  • 2つの関数テンプレートのそれぞれは、P または A とそれぞれ同じテンプレートパラメータを持ちます。
  • 各関数テンプレートは、単一の関数パラメータを持ち、その型は X の特殊化であり、それぞれの関数テンプレートのテンプレートパラメータに対応するテンプレート引数を持っています。ここで、関数テンプレートのテンプレートパラメータリスト内の各テンプレートパラメータ PP に対して、対応するテンプレート引数 AA が形成されますPP がパラメータパックを宣言する場合、AA はパック展開 PP... です。そうでない場合、(C++11以降) AA は id-expression PP です。

書き換えが無効な型を生成する場合、PA よりも少なくとも特殊化されていません。

template<typename T>
struct eval;                     // primary template
 
template<template<typename, typename...> class TT, typename T1, typename... Rest>
struct eval<TT<T1, Rest...>> {}; // partial specialization of 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: matches partial specialization of eval
eval<B<int, float>> eB; // OK: matches partial specialization of eval
eval<C<17>> eC;         // error: C does not match TT in partial specialization
                        // because TT's first parameter is a
                        // type template parameter, while 17 does not name a type
eval<D<int, 17>> eD;    // error: D does not match TT in partial specialization
                        // because TT's second parameter is a
                        // type parameter pack, while 17 does not name a type
eval<E<int, float>> eE; // error: E does not match TT in partial specialization
                        // because E's third (default) parameter is a non-type

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; // OK
X<B> xb; // OK after P0522R0
         // Error earlier: not an exact match
X<C> xc; // OK after P0522R0
         // Error earlier: not an exact match
 
template<template<class...> class Q> class Y { /* ... */ };
Y<A> ya; // OK
Y<B> yb; // OK
Y<C> yc; // OK
 
template<auto n> class D { /* ... */ };   // note: C++17
template<template<int> class R> class Z { /* ... */ };
Z<D> zd; // OK after P0522R0: the template parameter
         // is more specialized than the template argument
 
template<int> struct SI { /* ... */ };
template<template<auto> class> void FA(); // note: C++17
FA<SI>(); // Error

[edit] デフォルトテンプレート引数

デフォルトテンプレート引数は、パラメータリストで = 記号の後に指定されます。デフォルトはあらゆる種類のテンプレートパラメータ (型、非型、またはテンプレート)、ただしパラメータパックには指定できません(C++11以降) に指定できます。

プライマリクラステンプレート、プライマリ変数テンプレート、(C++14以降) またはエイリアステンプレートのテンプレートパラメータにデフォルトが指定されている場合、後続の各テンプレートパラメータにはデフォルト引数が必要です。ただし、最後の1つはテンプレートパラメータパックである場合があります(C++11以降)。関数テンプレートでは、デフォルトの後に続くパラメータに制限はありません。パラメータパックの後にさらに型パラメータが続くのは、それらにデフォルトがあるか、関数引数から推論できる場合に限られます(C++11以降)

デフォルトパラメータは許可されていません。

(C++11まで)

フレンド関数テンプレート宣言では、宣言が定義であり、この翻訳単位にこの関数の他の宣言が存在しない場合にのみ、デフォルトテンプレート引数が許可されます。

(C++11以降)

宣言に現れるデフォルトテンプレート引数は、デフォルト関数引数と同様にマージされます。

template<typename T1, typename T2 = int> class A;
template<typename T1 = int, typename T2> class A;
 
// the above is the same as the following:
template<typename T1 = int, typename T2 = int> class A;

しかし、同じスコープ内で同じパラメータに2回デフォルト引数を指定することはできません。

template<typename T = int> class X;
template<typename T = int> class X {}; // error

非型テンプレートパラメータのデフォルトテンプレート引数を解析する場合、最初の非ネストされた > は、より大きい演算子としてではなく、テンプレートパラメータリストの終わりとして解釈されます。

template<int i = 3 > 4>   // syntax error
class X { /* ... */ };
 
template<int i = (3 > 4)> // OK
class Y { /* ... */ };

テンプレートテンプレートパラメータのテンプレートパラメータリストは、それ自身のデフォルト引数を持つことができ、それらはテンプレートテンプレートパラメータ自体がスコープ内にある場合にのみ有効です。

// class template, with a type template parameter with a default
template<typename T = float>
struct B {};
 
// template template parameter T has a parameter list, which
// consists of one type template parameter with a default
template<template<typename = float> typename T>
struct A
{
    void f();
    void g();
};
 
// out-of-body member function template definitions
 
template<template<typename TT> class T>
void A<T>::f()
{
    T<> t; // error: TT has no default in scope
}
 
template<template<typename TT = char> class T>
void A<T>::g()
{
    T<> t; // OK: t is 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; // error: C::TT is protected

テンプレートが関数を命名するために使用される場合を除き、デフォルトテンプレート引数の値が必要なときに暗黙的にインスタンス化されます。

template<typename T, typename U = int>
struct S {};
 
S<bool>* p; // The default argument for U is instantiated at this point
            // the type of p is S<bool, int>*
(C++14以降)

[edit] テンプレート引数の等価性

テンプレート引数の等価性は、2つのテンプレート識別子が同じであるかどうかを判断するために使用されます。

2つの値がテンプレート引数等価であるとは、それらが同じ型であり、かつ以下のいずれかの条件が満たされる場合です。

  • それらが整数型または列挙型であり、その値が同じである。
  • それらがポインタ型であり、同じポインタ値を持つ。
  • それらがメンバへのポインタ型であり、同じクラスメンバを参照するか、両方ともヌルメンバポインタ値である。
  • それらが左辺値参照型であり、同じオブジェクトまたは関数を参照する。
(C++11以降)
  • それらが浮動小数点型であり、その値が同一である。
  • それらが配列型である (この場合、配列はいくつかのクラス/共用体のメンバオブジェクトでなければなりません) とき、それらの対応する要素がテンプレート引数等価である。
  • それらが共用体型であり、どちらもアクティブメンバを持たないか、または同じアクティブメンバを持ち、そのアクティブメンバがテンプレート引数等価である。
  • それらがラムダクロージャ型である。
  • それらが非共用体クラス型であり、それらの対応する直接サブオブジェクトおよび参照メンバがテンプレート引数等価である。
(C++20以降)

[edit] 注釈

テンプレートパラメータでは、auto の有無によって、型制約が型パラメータと非型パラメータの両方に使用される場合があります。

template<typename>
concept C = true;
 
template<C,     // type parameter 
         C auto // non-type parameter
        >
struct S{};
 
S<int, 0> s;


(C++20以降)
機能テストマクロ 規格 機能
__cpp_nontype_template_parameter_auto 201606L (C++17) auto を使用した非型テンプレートパラメータの宣言
__cpp_template_template_args 201611L (c++17)
(DR)
テンプレートテンプレート引数のマッチング
__cpp_nontype_template_args 201411L (C++17) すべての非型テンプレート引数に対する定数評価を許可
201911L (C++20) 非型テンプレートパラメータにおけるクラス型と浮動小数点型

[edit]

#include <array>
#include <iostream>
#include <numeric>
 
// simple non-type template parameter
template<int N>
struct S { int a[N]; };
 
template<const char*>
struct S2 {};
 
// complicated non-type example
template
<
    char c,             // integral type
    int (&ra)[5],       // lvalue reference to object (of array type)
    int (*pf)(int),     // pointer to function
    int (S<10>::*a)[10] // pointer to member object (of type int[10])
>
struct Complicated
{
    // calls the function selected at compile time
    // and stores the result in the array selected at compile time
    void foo(char base)
    {
        ra[4] = pf(c - base);
    }
};
 
//  S2<"fail"> s2;        // error: string literal cannot be used
    char okay[] = "okay"; // static object with linkage
//  S2<&okay[0]> s3;      // error: array element has no linkage
    S2<okay> s4;          // works
 
int a[5];
int f(int n) { return n; }
 
// C++20: NTTP can be a literal class type
template<std::array arr>
constexpr
auto sum() { return std::accumulate(arr.cbegin(), arr.cend(), 0); }
 
// C++20: class template arguments are deduced at the call site
static_assert(sum<std::array<double, 8>{3, 1, 4, 1, 5, 9, 2, 6}>() == 31.0);
// C++20: NTTP argument deduction and CTAD
static_assert(sum<std::array{2, 7, 1, 8, 2, 8}>() == 28);
 
int main()
{
    S<10> s; // s.a is an array of 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

[edit] 欠陥報告

以下の動作変更を伴う欠陥報告が、以前に公開されたC++標準に遡って適用されました。

DR 適用対象 公開された動作 正しい動作
CWG 150
(P0522R0)
C++98 テンプレートテンプレート引数は、テンプレートテンプレートパラメータのリストと厳密に一致する必要がありました。
リストと厳密に一致
より特殊化された
も許可
CWG 184 C++98 テンプレートテンプレートパラメータのテンプレートパラメータがデフォルト引数を持つことが許可されているかどうかは未指定
パラメータはデフォルト引数を持つことが許可されているかどうかは未指定
仕様が追加されました
CWG 354 C++98 ヌルポインタ値は非型テンプレート引数にできませんでした 許可
CWG 1398 C++11 非型テンプレート引数は型 std::nullptr_t を持つことができませんでした 許可
CWG 1570 C++98 非型テンプレート引数はサブオブジェクトのアドレスを指定できました 許可されなくなった。
CWG 1922 C++98 名前が注入されたクラス名であるクラステンプレートが、以前の宣言でデフォルト引数を使用できるかどうかは不明でした。
注入されたクラス名
許可
CWG 2032 C++14 変数テンプレートの場合、デフォルト引数を持つテンプレートパラメータの後のテンプレートパラメータに制限はありませんでした。
デフォルト引数
同じ制限を適用
クラステンプレートの場合と同じ
およびエイリアステンプレートの場合と同じ
CWG 2542 C++20 クロージャ型が構造型であるかどうかは不明でした 構造型ではない
CWG 2845 C++20 クロージャ型は構造型ではありませんでした 構造型である
キャプチャがない場合
P2308R1 C++11
C++20
1. 非型テンプレート引数ではリスト初期化が許可されていませんでした (C++11)
    非型テンプレート引数 (C++11)
2. クラス型の非型テンプレートパラメータがどのように初期化されるかは不明でした (C++20)
    パラメータがどのように初期化されるか (C++20)
1. 許可されました
2. 明確化されました
English 日本語 中文(简体) 中文(繁體)