Namespaces
Variants

Template parameters

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

Chaque template est paramétré par un ou plusieurs paramètres de template.

Chaque paramètre dans template-parameter-list (voir syntaxe de déclaration de template ) appartient à l'une des catégories suivantes :

  • paramètre de modèle constant
  • paramètre de modèle de type
  • paramètre de modèle de modèle

Table des matières

Paramètre de modèle constant

Également appelé non-type template parameter (voir ci-dessous ).

type name  (facultatif) (1)
type name  (facultatif) = default (2)
type ... name  (facultatif) (3) (depuis C++11)
type - un des types suivants :
  • un type structurel (voir ci-dessous)
(depuis C++17)
(depuis C++20)
name - le nom du paramètre de template constant
default - l' argument de template par défaut
1) Un paramètre de modèle constant.
2) Un paramètre de modèle constant avec un argument de modèle par défaut.
3) Un parameter pack de modèle constant.


Un type structurel est l'un des types suivants (éventuellement qualifié cv, les qualificateurs sont ignorés) :

(depuis C++11)
  • toutes les classes de base et les membres de données non statiques sont publics et non modifiables et
  • les types de toutes les classes de base et membres de données non statiques sont des types structurels ou des tableaux (éventuellement multidimensionnels) de ceux-ci.
(depuis C++20)

Les types de tableau et de fonction peuvent être écrits dans une déclaration de modèle, mais ils sont automatiquement remplacés par un pointeur vers un objet et un pointeur vers une fonction selon le cas.

Lorsque le nom d'un paramètre de modèle constant est utilisé dans une expression au sein du corps du modèle de classe, il s'agit d'une prvalue non modifiable, sauf si son type était un type référence lvalue , ou sauf si son type est un type classe (depuis C++20) .

Un paramètre de template de la forme class Foo n'est pas un paramètre de template constant sans nom de type Foo , même si par ailleurs class Foo est un spécificateur de type élaboré et que class Foo x ; déclare x comme étant de type Foo .

Un identifiant qui nomme un paramètre de template constant de type classe T désigne un objet de durée de stockage statique de type const T , appelé objet paramètre de template , qui est équivalent en argument de template à l'argument de template correspondant après conversion au type du paramètre de template. Aucun deux objets paramètres de template ne sont équivalents en argument de template.

struct A
{
    friend bool operator==(const A&, const A&) = default;
};
template<A a>
void f()
{
    &a;                       // OK
    const A& ra = a, &rb = a; // Les deux liés au même objet paramètre de template
    assert(&ra == &rb);       // passe
}
(depuis C++20)

Paramètre de modèle de type

type-parameter-key name  (facultatif) (1)
type-parameter-key name  (facultatif) = default (2)
type-parameter-key ... name  (facultatif) (3) (depuis C++11)
type-constraint name  (facultatif) (4) (depuis C++20)
type-constraint name  (facultatif) = default (5) (depuis C++20)
type-constraint ... name  (facultatif) (6) (depuis C++20)
type-parameter-key - soit typename ou class . Il n'y a aucune différence entre ces mots-clés dans une déclaration de paramètre de modèle de type
type-constraint - soit le nom d'un concept ou le nom d'un concept suivi d'une liste d'arguments de modèle (entre chevrons). Dans les deux cas, le nom du concept peut être optionnellement qualifié
name - le nom du paramètre de modèle de type
default - l' argument de modèle par défaut
1) Un paramètre de template de type sans valeur par défaut.
template<class T>
class My_vector { /* ... */ };
2) Un paramètre de template de type avec une valeur par défaut.
template<class T = void>
struct My_op_functor { /* ... */ };
3) Un pack de paramètres de modèle de type parameter pack .
template<typename... Ts>
class My_tuple { /* ... */ };
4) Un paramètre de modèle de type contraint sans valeur par défaut.
template<My_concept T>
class My_constrained_vector { /* ... */ };
5) Un paramètre de modèle de type contraint avec une valeur par défaut.
template<My_concept T = void>
class My_constrained_op_functor { /* ... */ };
6) Un modèle de type contraint parameter pack .
template<My_concept... Ts>
class My_constrained_tuple { /* ... */ };


Le nom du paramètre est facultatif :

// Déclarations des modèles montrés ci-dessus :
template<class>
class My_vector;
template<class = void>
struct My_op_functor;
template<typename...>
class My_tuple;

Dans le corps de la déclaration du template, le nom d'un paramètre de type est un typedef-name qui alias le type fourni lors de l'instanciation du template.

Chaque paramètre contraint P dont la contrainte-de-type est Q désignant le concept C introduit une expression-de-contrainte E selon les règles suivantes :

  • si Q est C (sans liste d'arguments),
  • si P n'est pas un paramètre pack, E est simplement C<P>
  • sinon, P est un paramètre pack, E est une expression de repli (C<P> && ...)
  • si Q est C<A1,A2...,AN> , alors E est respectivement C<P,A1,A2,...AN> ou (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> && ...)
(depuis C++20)

Paramètre template template

template < liste-de-paramètres > clé-type-paramètre nom  (optionnel) (1)
template < liste-de-paramètres > clé-type-paramètre nom  (optionnel) = valeur-par-défaut (2)
template < liste-de-paramètres > clé-type-paramètre ... nom  (optionnel) (3) (depuis C++11)
type-parameter-key - class ou typename (depuis C++17)
1) Un paramètre template template avec un nom optionnel.
2) Un paramètre template template avec un nom optionnel et une valeur par défaut.
3) Un pack de paramètres de template template parameter pack avec un nom optionnel.


Dans le corps de la déclaration du template, le nom de ce paramètre est un nom-de-template (et nécessite des arguments pour être instancié).

template<typename T>
class my_array {};
// deux paramètres de type template et un paramètre template template :
template<typename K, typename V, template<typename> typename C = my_array>
class Map
{
    C<K> key;
    C<V> value;
};

Résolution des noms pour les paramètres de template

Le nom d'un paramètre de modèle n'est pas autorisé à être redéclaré dans sa portée (y compris les portées imbriquées). Un paramètre de modèle ne peut pas avoir le même nom que le nom du modèle.

template<class T, int N>
class Y
{
    int T;      // erreur : paramètre de template redéclaré
    void f()
    {
        char T; // erreur : paramètre de template redéclaré
    }
};
template<class X>
class X; // erreur : paramètre de template redéclaré

Dans la définition d'un membre d'un modèle de classe qui apparaît en dehors de la définition du modèle de classe, le nom d'un membre du modèle de classe masque le nom d'un paramètre de modèle de tout modèle de classe englobant, mais pas un paramètre de modèle du membre si le membre est un modèle de classe ou de fonction.

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; // B de A, pas le paramètre template
}
template<class B>
template<class C>
void A<B>::g(C)
{
    B b; // B de A, pas le paramètre template
    C c; // le paramètre template C, pas C de A
}

Dans la définition d'un membre d'un modèle de classe qui apparaît en dehors de l'espace de noms contenant la définition du modèle de classe, le nom d'un paramètre de modèle masque le nom d'un membre de cet espace de noms.

namespace N
{
    class C {};
    template<class T>
    class B
    {
        void f(T);
    };
}
template<class C>
void N::B<C>::f(C)
{
    C b; // C est le paramètre template, pas N::C
}

Dans la définition d'un modèle de classe ou dans la définition d'un membre d'un tel modèle qui apparaît en dehors de la définition du modèle, pour chaque classe de base non- dépendante , si le nom de la classe de base ou le nom d'un membre de la classe de base est identique au nom d'un paramètre de modèle, le nom de la classe de base ou le nom du membre masque le nom du paramètre de modèle.

struct A
{
    struct B {};
    int C;
    int Y;
};
template<class B, class C>
struct X : A
{
    B b; // B de A
    C b; // erreur : C de A n'est pas un nom de type
};

Arguments de modèle par défaut

Les arguments par défaut des modèles sont spécifiés dans les listes de paramètres après le = signe. Les valeurs par défaut peuvent être spécifiées pour tout type de paramètre de modèle (type, constante ou template) , mais pas pour les parameter packs (depuis C++11) .

Si une valeur par défaut est spécifiée pour un paramètre de template d'un template de classe primaire , d'un template de variable primaire, (depuis C++14) ou d'un template d'alias, chaque paramètre de template suivant doit avoir un argument par défaut , sauf le tout dernier qui peut être un parameter pack de template (depuis C++11) . Dans un template de fonction, il n'y a aucune restriction sur les paramètres qui suivent un paramètre par défaut , et un parameter pack peut être suivi par d'autres paramètres de type seulement s'ils ont des valeurs par défaut ou peuvent être déduits des arguments de la fonction (depuis C++11) .

Les paramètres par défaut ne sont pas autorisés

(jusqu'à C++11)

Dans une déclaration de fonction template amie, les arguments template par défaut sont autorisés uniquement si la déclaration est une définition, et aucune autre déclaration de cette fonction n'apparaît dans cette unité de traduction.

(since C++11)

Les arguments de template par défaut qui apparaissent dans les déclarations sont fusionnés de manière similaire aux arguments de fonction par défaut :

template<typename T1, typename T2 = int> class A;
template<typename T1 = int, typename T2> class A;
// ce qui précède est équivalent à ce qui suit :
template<typename T1 = int, typename T2 = int> class A;

Mais le même paramètre ne peut pas recevoir d'arguments par défaut deux fois dans la même portée :

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

Lors de l'analyse d'un argument de template par défaut pour un paramètre de template constant, le premier > non imbriqué est considéré comme la fin de la liste des paramètres du template plutôt qu'un opérateur supérieur à :

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

Les listes de paramètres template des paramètres template template peuvent avoir leurs propres arguments par défaut, qui ne sont effectifs que là où le paramètre template template lui-même est dans la portée :

// modèle de classe, avec un paramètre de type template ayant une valeur par défaut
template<typename T = float>
struct B {};
// le paramètre template template T a une liste de paramètres, qui
// consiste en un paramètre de type template avec une valeur par défaut
template<template<typename = float> typename T>
struct A
{
    void f();
    void g();
};
// définitions de fonctions membres template hors du corps
template<template<typename TT> class T>
void A<T>::f()
{
    T<> t; // erreur : TT n'a pas de valeur par défaut dans la portée
}
template<template<typename TT = char> class T>
void A<T>::g()
{
    T<> t; // OK : t est T<char>
}

Accès aux membres pour les noms utilisés dans un paramètre de template par défaut est vérifié lors de la déclaration, et non au point d'utilisation :

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; // erreur : C::TT est protégé

L'argument template par défaut est implicitement instancié lorsque la valeur de cet argument par défaut est nécessaire, sauf si le template est utilisé pour nommer une fonction :

template<typename T, typename U = int>
struct S {};
S<bool>* p; // L'argument par défaut pour U est instancié à ce point
            // le type de p est S<bool, int>*
(depuis C++14)

Notes

Avant C++26, les paramètres de template constants étaient appelés paramètres de template non-type dans la terminologie standard. La terminologie a été modifiée par P2841R6 / PR#7587 .

Dans les paramètres de template, les contraintes de type peuvent être utilisées pour les paramètres de type et les paramètres constants, selon la présence de auto .

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


(depuis C++20)
Macro de test de fonctionnalité Valeur Std Fonctionnalité
__cpp_nontype_template_parameter_auto 201606L (C++17) Déclaration des paramètres de template constants avec auto
__cpp_nontype_template_args 201411L (C++17) Autoriser l'évaluation constante pour tous les arguments de template constants
201911L (C++20) Types de classes et types à virgule flottante dans les paramètres de template constants

Exemples

#include <array>
#include <iostream>
#include <numeric>
// paramètre de template constant simple
template<int N>
struct S { int a[N]; };
template<const char*>
struct S2 {};
// exemple constant complexe
template
<
    char c,             // type intégral
    int (&ra)[5],       // référence lvalue vers objet (de type tableau)
    int (*pf)(int),     // pointeur vers fonction
    int (S<10>::*a)[10] // pointeur vers membre objet (de type int[10])
>
struct Complicated
{
    // appelle la fonction sélectionnée à la compilation
    // et stocke le résultat dans le tableau sélectionné à la compilation
    void foo(char base)
    {
        ra[4] = pf(c - base);
    }
};
//  S2<"fail"> s2;        // erreur : littéral de chaîne ne peut être utilisé
    char okay[] = "okay"; // objet statique avec liaison
//  S2<&okay[0]> s3;      // erreur : élément de tableau n'a pas de liaison
    S2<okay> s4;          // fonctionne
int a[5];
int f(int n) { return n; }
// C++20 : NTTP peut être un type de classe littérale
template<std::array arr>
constexpr
auto sum() { return std::accumulate(arr.cbegin(), arr.cend(), 0); }
// C++20 : les arguments des templates de classe sont déduits au site d'appel
static_assert(sum<std::array<double, 8>{3, 1, 4, 1, 5, 9, 2, 6}>() == 31.0);
// C++20 : déduction d'argument NTTP et CTAD
static_assert(sum<std::array{2, 7, 1, 8, 2, 8}>() == 28);
int main()
{
    S<10> s; // s.a est un tableau de 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';
}

Sortie :

42

Rapports de défauts

Les rapports de défauts modifiant le comportement suivants ont été appliqués rétroactivement aux normes C++ précédemment publiées.

DR Appliqué à Comportement publié Comportement correct
CWG 184 C++98 si les paramètres template des paramètres template template
sont autorisés à avoir des arguments par défaut n'est pas spécifié
spécification ajoutée
CWG 1922 C++98 il n'était pas clair si un template de classe dont le nom est un
nom de classe injecté peut utiliser les arguments par défaut dans les déclarations antérieures
autorisé
CWG 2032 C++14 pour les templates de variable, il n'y avait aucune restriction sur les paramètres
template après un paramètre template avec un argument par défaut
appliquer la même restriction
que pour les templates de classe
et les alias templates
CWG 2542 C++20 il n'était pas clair si le type de fermeture est structurel il n'est pas structurel
CWG 2845 C++20 le type de fermeture n'était pas structurel il est structurel
s'il est sans capture