成员模板
来自 cppreference.cn
模板声明(类, 函数,以及 变量(since 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 |