Spec-Zone.ru › C++

Шаблоны-члены

Объявления шаблонов (класса, функции и переменных(начиная с C++14)) могут находиться в описании членов любого класса, структуры или объединения, которые не являются локальными классами.

#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));
}

Вывод:

1 2 3 a b c

Частичные специализации шаблона-члена могут находиться как в области видимости класса, так и в области видимости охватывающего пространства имён. Явные специализации могут находиться в любой области видимости, в которой может находиться первичный шаблон.

struct A
{
    template<class T> struct B;        // primary member template
    template<class T> struct B<T*> {}; // OK: partial specialization
//  template<> struct B<int*> {};      // OK via CWG 727: full specialization
};
template<> struct A::B<int*> {};       // OK
template<class T> struct A::B<T&> {};  // OK

Если охватывающее объявление класса, в свою очередь, является шаблоном класса, то при определении шаблона-члена вне тела класса он принимает два набора параметров шаблона: один для охватывающего класса, а другой — для самого себя:

template<typename T1>
struct string
{
    // member template function
    template<typename T2>
    int compare(const T2&);
    // constructors can be templates too
    template<typename T2>
    string(const std::basic_string<T2>& s) { /*...*/ }
};
// out of class definition of string<T1>::compare<T2> 
template<typename T1> // for the enclosing class template
template<typename T2> // for the member template
int string<T1>::compare(const T2& s) { /* ... */ }

Шаблоны функций-членов

Деструкторы и конструкторы копирования не могут быть шаблонами. Если объявлен шаблон конструктора, который может быть создан с сигнатурой типа конструктора копирования, вместо него используется неявно объявленный конструктор копирования.

Шаблон функции-члена не может быть виртуальным, а шаблон функции-члена в производном классе не может переопределять виртуальную функцию-член базового класса.

class Base
{
    virtual void f(int);
};

struct Derived : Base
{
    // this member template does not override Base::f
    template<class T> void f(T);

    // non-template member override can call the template:
    void f(int i) override
    {
         f<>(i);
    }
};

Можно объявить функцию-член, не являющуюся шаблоном, и функцию-член-шаблон с одинаковым именем. В случае конфликта (когда некоторая специализация шаблона точно соответствует сигнатуре функции, не являющейся шаблоном) использование этого имени и типа относится к функции-члену, не являющейся шаблоном, если не указан явный список аргументов шаблона.

template<typename T>
struct A
{
    void f(int); // non-template member
    
    template<typename T2>
    void f(T2); // member template
};

// template member definition
template<typename T>
template<typename T2>
void A<T>::f(T2)
{
    // some code
}

int main()
{
    A<char> ac;
    ac.f('c'); // calls template function A<char>::f<char>(char)
    ac.f(1);   // calls non-template function A<char>::f(int)
    ac.f<>(1); // calls template function A<char>::f<int>(int)
}


Определение шаблона функции-члена вне класса должно быть эквивалентно объявлению внутри класса (определение эквивалентности см. в разделе о перегрузке шаблонов функций), иначе оно считается перегрузкой.

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: equivalent declaration
template<class V>
V X::good(V n) { return n; }

// Error: not equivalent to any of the declarations inside X
template<class T>
T X::bad(typename identity<T>::type n) { return n; }

Шаблоны функций преобразования

Пользовательская функция преобразования может быть шаблоном.

struct A
{
    template<typename T>
    operator T*(); // conversion to pointer to any type
};

// out-of-class definition
template<typename T>
A::operator T*() { return nullptr; }

// explicit specialization for char*
template<>
A::operator char*() { return nullptr; }

// explicit instantiation
template A::operator void*();

int main()
{
    A a;
    int* ip = a.operator int*(); // explicit call to A::operator int*()
}

При разрешении перегрузки специализации шаблонов функций преобразования не обнаруживаются посредством поиска имени. Вместо этого рассматриваются все видимые шаблоны функций преобразования, а каждая специализация, полученная в результате выведения аргументов шаблона (для которого предусмотрены специальные правила для шаблонов функций преобразования), используется так, как если бы она была найдена посредством поиска имени.

Using-объявления в производных классах не могут ссылаться на специализации шаблонов функций преобразования из базовых классов.

Пользовательская функция преобразования-шаблон не может иметь выводимый тип возвращаемого значения:

struct S
{
    operator auto() const { return 10; } // OK
    template<class T> operator auto() const { return 42; } // error
};
(начиная с C++14)

Шаблоны переменных-членов

Объявление шаблона переменной может находиться в области видимости класса; в этом случае оно объявляет шаблон статического члена данных. Подробности см. в разделе о шаблонах переменных.

(начиная с C++14)

Отчёты об ошибках

Следующие отчёты об ошибках, изменяющие поведение, были ретроактивно применены к ранее опубликованным стандартам C++.

DR Применён к Поведение согласно опубликованной версии Корректное поведение
CWG 1878 C++14 operator auto технически допускался operator auto запрещён

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/language/member_template

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API