名稱空間
變體
操作

成員模板

來自 cppreference.com
< cpp‎ | 語言
 
 
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++ 標準。

缺陷報告 應用於 釋出時的行為 正確的行為
CWG 1878 C++14 operator auto 在技術上是允許的 operator auto 被禁止
English 日本語 中文(简体) 中文(繁體)