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

Las declaraciones de plantilla ( class , function , y variables (since C++14) ) pueden aparecer dentro de una especificación de miembro de cualquier class, struct o union que no sean clases locales .

#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
struct Printer
{
    // funtor genérico
    std::ostream& os;
    Printer(std::ostream& os) : os(os) {}
    template<typename T>
    void operator()(const T& obj) { os << obj << ' '; } // plantilla de miembro
};
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));
}

Salida:

1 2 3 a b c

Las especializaciones parciales de plantillas de miembros pueden aparecer tanto en el ámbito de la clase como en el ámbito del espacio de nombres envolvente. Las especializaciones explícitas pueden aparecer en cualquier ámbito en el que pueda aparecer la plantilla principal.

struct A
{
    template<class T> struct B;        // plantilla de miembro primaria
    template<class T> struct B<T*> {}; // OK: especialización parcial
//  template<> struct B<int*> {};      // OK via CWG 727: especialización completa
};
template<> struct A::B<int*> {};       // OK
template<class T> struct A::B<T&> {};  // OK

Si la declaración de la clase envolvente es, a su vez, una plantilla de clase, cuando una plantilla de miembro se define fuera del cuerpo de la clase, toma dos conjuntos de parámetros de plantilla: uno para la clase envolvente y otro para sí misma:

template<typename T1>
struct string
{
    // función de plantilla miembro
    template<typename T2>
    int compare(const T2&);
    // los constructores también pueden ser plantillas
    template<typename T2>
    string(const std::basic_string<T2>& s) { /*...*/ }
};
// definición externa de string<T1>::compare<T2>
template<typename T1> // para la plantilla de clase contenedora
template<typename T2> // para la plantilla miembro
int string<T1>::compare(const T2& s) { /* ... */ }

Contenidos

Plantillas de funciones miembro

Destructores y constructores de copia no pueden ser plantillas. Si se declara un constructor plantilla que podría instanciarse con la firma de tipo de un constructor de copia, se utiliza en su lugar el constructor de copia declarado implícitamente .

Una función miembro plantilla no puede ser virtual, y una función miembro plantilla en una clase derivada no puede anular una función miembro virtual de la clase base.

class Base
{
    virtual void f(int);
};
struct Derived : Base
{
    // esta plantilla de miembro no reemplaza Base::f
    template<class T> void f(T);
    // el reemplazo de miembro no plantilla puede llamar a la plantilla:
    void f(int i) override
    {
         f<>(i);
    }
};

Se pueden declarar una función miembro no plantilla y una función miembro plantilla con el mismo nombre. En caso de conflicto (cuando alguna especialización de plantilla coincide exactamente con la firma de la función no plantilla), el uso de ese nombre y tipo se refiere a la función miembro no plantilla a menos que se proporcione una lista explícita de argumentos de plantilla.

template<typename T>
struct A
{
    void f(int); // miembro no plantilla
    template<typename T2>
    void f(T2); // plantilla de miembro
};
// definición de miembro plantilla
template<typename T>
template<typename T2>
void A<T>::f(T2)
{
    // algún código
}
int main()
{
    A<char> ac;
    ac.f('c'); // llama a la función plantilla A<char>::f<char>(char)
    ac.f(1);   // llama a la función no plantilla A<char>::f(int)
    ac.f<>(1); // llama a la función plantilla A<char>::f<int>(int)
}


Una definición fuera de la clase de una plantilla de función miembro debe ser equivalente a la declaración dentro de la clase (consulte sobrecarga de plantillas de función para la definición de equivalencia), de lo contrario se considera una sobrecarga.

struct X
{
    template<class T> T good(T n);
    template<class T> T bad(T n);
};
template<class T> struct identity { using type = T; };
// CORRECTO: declaración equivalente
template<class V>
V X::good(V n) { return n; }
// ERROR: no equivalente a ninguna de las declaraciones dentro de X
template<class T>
T X::bad(typename identity<T>::type n) { return n; }

Plantillas de funciones de conversión

Una función de conversión definida por el usuario puede ser una plantilla.

struct A
{
    template<typename T>
    operator T*(); // conversión a puntero de cualquier tipo
};
// definición fuera de la clase
template<typename T>
A::operator T*() { return nullptr; }
// especialización explícita para char*
template<>
A::operator char*() { return nullptr; }
// instanciación explícita
template A::operator void*();
int main()
{
    A a;
    int* ip = a.operator int*(); // llamada explícita a A::operator int*()
}

Durante la resolución de sobrecarga , las especializaciones de plantillas de funciones de conversión no se encuentran mediante búsqueda por nombre . En su lugar, se consideran todas las plantillas de funciones de conversión visibles, y cada especialización producida por deducción de argumentos de plantilla (que tiene reglas especiales para plantillas de funciones de conversión) se utiliza como si se hubiera encontrado mediante búsqueda por nombre.

Las declaraciones using en clases derivadas no pueden hacer referencia a especializaciones de funciones de conversión de plantilla de clases base.

Una función de conversión definida por el usuario no puede tener un tipo de retorno deducido:

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

Plantillas de variables miembro

Una declaración de plantilla de variable puede aparecer en el ámbito de clase, en cuyo caso declara una plantilla de miembro de datos estático. Consulte plantillas de variables para más detalles.

(desde C++14)

Informes de defectos

Los siguientes informes de defectos que modifican el comportamiento se aplicaron retroactivamente a los estándares publicados anteriormente de C++.

DR Aplicado a Comportamiento publicado Comportamiento correcto
CWG 1878 C++14 operator auto estaba técnicamente permitido operator auto prohibido