Namespaces
Variants

Member templates

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

Les déclarations de modèles ( class , function , et variables (depuis C++14) ) peuvent apparaître dans la spécification de membre de toute classe, structure ou union qui ne sont pas des classes locales .

#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
struct Printer
{
    // generic functor
    std::ostream& os;
    Printer(std::ostream& os) : os(os) {}
    template<typename T>
    void operator()(const T& obj) { os << obj << ' '; } // member template
};
int main()
{
    std::vector<int> v{1,2,3};
    std::for_each(v.begin(), v.end(), Printer(std::cout));
    std::string s{"abc"};
    std::ranges::for_each(s, Printer(std::cout));
}

Sortie :

1 2 3 a b c

Les spécialisations partielles des modèles membres peuvent apparaître à la fois au niveau de la classe et au niveau de l'espace de noms englobant. Les spécialisations explicites peuvent apparaître dans toute portée où le modèle principal peut apparaître.

struct A
{
    template<class T> struct B;        // modèle de membre primaire
    template<class T> struct B<T*> {}; // OK : spécialisation partielle
//  template<> struct B<int*> {};      // OK via CWG 727 : spécialisation complète
};
template<> struct A::B<int*> {};       // OK
template<class T> struct A::B<T&> {};  // OK

Si la déclaration de la classe englobante est, à son tour, un modèle de classe, lorsqu'un modèle de membre est défini en dehors du corps de la classe, il prend deux ensembles de paramètres de modèle : un pour la classe englobante, et un autre pour lui-même :

template<typename T1>
struct string
{
    // fonction membre template
    template<typename T2>
    int compare(const T2&);
    // les constructeurs peuvent aussi être des templates
    template<typename T2>
    string(const std::basic_string<T2>& s) { /*...*/ }
};
// définition hors classe de string<T1>::compare<T2>
template<typename T1> // pour la classe template englobante
template<typename T2> // pour le membre template
int string<T1>::compare(const T2& s) { /* ... */ }

Table des matières

Modèles de fonctions membres

Destructeurs et constructeurs de copie ne peuvent pas être des modèles. Si un constructeur modèle est déclaré qui pourrait être instancié avec la signature de type d'un constructeur de copie, le constructeur de copie implicitement déclaré est utilisé à la place.

Une fonction membre template ne peut pas être virtuelle, et une fonction membre template dans une classe dérivée ne peut pas remplacer une fonction membre virtuelle de la classe de base.

class Base
{
    virtual void f(int);
};
struct Derived : Base
{
    // ce modèle de fonction membre ne remplace pas Base::f
    template<class T> void f(T);
    // la fonction membre non-modèle qui remplace peut appeler le modèle :
    void f(int i) override
    {
         f<>(i);
    }
};

Une fonction membre non template et une fonction membre template avec le même nom peuvent être déclarées. En cas de conflit (lorsqu'une spécialisation de template correspond exactement à la signature de la fonction non template), l'utilisation de ce nom et de ce type fait référence à la fonction membre non template, sauf si une liste d'arguments de template explicite est fournie.

template<typename T>
struct A
{
    void f(int); // membre non-template
    template<typename T2>
    void f(T2); // membre template
};
// définition du membre template
template<typename T>
template<typename T2>
void A<T>::f(T2)
{
    // code quelconque
}
int main()
{
    A<char> ac;
    ac.f('c'); // appelle la fonction template A<char>::f<char>(char)
    ac.f(1);   // appelle la fonction non-template A<char>::f(int)
    ac.f<>(1); // appelle la fonction template A<char>::f<int>(int)
}


Une définition hors-classe d'un modèle de fonction membre doit être équivalente à la déclaration à l'intérieur de la classe (voir la surcharge de modèles de fonction pour la définition de l'équivalence), sinon elle est considérée comme une surcharge.

struct X
{
    template<class T> T good(T n);
    template<class T> T bad(T n);
};
template<class T> struct identity { using type = T; };
// OK : déclaration équivalente
template<class V>
V X::good(V n) { return n; }
// Erreur : non équivalent à l'une des déclarations dans X
template<class T>
T X::bad(typename identity<T>::type n) { return n; }

Modèles de fonctions de conversion

Une fonction de conversion définie par l'utilisateur peut être un modèle.

struct A
{
    template<typename T>
    operator T*(); // conversion vers pointeur de n'importe quel type
};
// définition hors-classe
template<typename T>
A::operator T*() { return nullptr; }
// spécialisation explicite pour char*
template<>
A::operator char*() { return nullptr; }
// instanciation explicite
template A::operator void*();
int main()
{
    A a;
    int* ip = a.operator int*(); // appel explicite à A::operator int*()
}

Lors de la résolution de surcharge , les spécialisations des modèles de fonction de conversion ne sont pas trouvées par recherche de nom . Au lieu de cela, tous les modèles de fonction de conversion visibles sont considérés, et chaque spécialisation produite par déduction d'argument de modèle (qui possède des règles spéciales pour les modèles de fonction de conversion) est utilisée comme si elle était trouvée par recherche de nom.

Les déclarations using dans les classes dérivées ne peuvent pas faire référence aux spécialisations des fonctions de conversion template des classes de base.

Une fonction de conversion définie par l'utilisateur sous forme de modèle ne peut pas avoir un type de retour déduit :

struct S
{
    operator auto() const { return 10; } // OK
    template<class T> operator auto() const { return 42; } // error
};
(depuis C++14)

Modèles de variables membres

Une déclaration de modèle de variable peut apparaître au niveau de la portée de la classe, auquel cas elle déclare un modèle de membre de données statique. Voir modèles de variables pour plus de détails.

(depuis C++14)

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 corrigé
CWG 1878 C++14 operator auto était techniquement autorisé operator auto interdit