名前空間
変種
操作

メンバテンプレート

提供: cppreference.com
< cpp‎ | language
 
 
C++言語
一般的なトピック
フロー制御
条件付き実行文
繰り返し文 (ループ)
ジャンプ文
関数
関数宣言
ラムダ関数宣言
inline 指定子
例外指定(C++20未満)
noexcept 指定子(C++11)
例外
名前空間
指定子
decltype(C++11)
auto(C++11)
alignas(C++11)
記憶域期間指定子
初期化
代替表現
リテラル
ブーリアン - 整数 - 浮動小数点
文字 - 文字列 - nullptr(C++11)
ユーザ定義(C++11)
ユーティリティ
属性(C++11)
typedef 宣言
型エイリアス宣言(C++11)
キャスト
暗黙の変換 - 明示的な変換
static_cast - dynamic_cast
const_cast - reinterpret_cast
メモリ確保
クラス
クラス固有の関数特性
特別なメンバ関数
テンプレート
その他
 
 

テンプレートの宣言 (クラス関数、および変数(C++14以上)) は、ローカルクラスでない任意のクラス、構造体、または共用体の中でも行うことができます。

#include <iostream>#include <vector>#include <algorithm>   struct Printer {// 総称ファンクタstd::ostream& os; Printer(std::ostream& os): os(os){}template<typename T>void operator()(const T& obj){ os << obj <<' ';}// メンバテンプレート};   int main(){std::vector<int> v ={1,2,3};std::for_each(v.begin(), v.end(), Printer(std::cout));std::string s ="abc";std::for_each(s.begin(), s.end(), Printer(std::cout));}

出力:

1 2 3 a b c

メンバテンプレートの部分特殊化はクラススコープと囲っている名前空間スコープのどちらでもできますが、明示的特殊化は囲っている名前空間スコープでのみできます。

struct A {template<class T>struct B;// プライマリメンバテンプレートtemplate<class T>struct B<T*>{};// OK、部分特殊化// template<> struct B<int*> { }; // エラー、完全特殊化};template<>struct A::B<int*>{};// OKtemplate<class T>struct A::B<T&>{};// OK

囲っているクラスの宣言もまたクラステンプレートである場合は、メンバテンプレートをクラス本体の外側で定義するとき、テンプレート仮引数のセットを2つ取ります (ひとつは囲っているクラス用で、もうひとつは自分用です)。

template<typename T1>struct string {// メンバテンプレート関数template<typename T2>int compare(const T2&);// コンストラクタもテンプレートにできますtemplate<typename T2> string(conststd::basic_string<T2>& s){/*...*/}};// string<T1>::compare<T2> のクラス外側の定義template<typename T1>// 囲っているクラステンプレート用template<typename T2>// メンバテンプレート用int string<T1>::compare(const T2& s){/* ... */}

目次

[編集]メンバ関数テンプレート

デストラクタおよびコピーコンストラクタはテンプレートにできません。 テンプレートコンストラクタをコピーコンストラクタの型シグネチャで実体化できるように宣言しても、代わりに暗黙に宣言されたコピーコンストラクタが使用されます。

メンバ関数テンプレートは仮想にできません。 また、派生クラスのメンバ関数テンプレートは基底クラスの仮想メンバ関数をオーバーライドできません。

class Base {virtualvoid f(int);};struct Derived : Base {// このメンバテンプレートは Base::f をオーバーライドしません。template<class T>void f(T);   // 非テンプレートメンバのオーバーライドがテンプレートを呼ぶことはできます。void f(int i) override { f<>(i);}};

同じ名前を持つ非テンプレートメンバ関数とテンプレートメンバ関数を宣言しても構いません。 衝突した場合 (何らかのテンプレート特殊化が非テンプレート関数のシグネチャと正確に一致したとき) は、明示的なテンプレート引数リストが与えられない限り、非テンプレートメンバを参照します。

template<typename T>struct A {void f(int);// 非テンプレートメンバ   template<typename T2>void f(T2);// メンバテンプレート};   // メンバテンプレートの定義template<typename T>template<typename T2>void A<T>::f(T2){// 何らかのコード}   int main(){ A<char> ac; ac.f('c');// テンプレート関数 A<char>::f<char>(int) を呼びます。 ac.f(1);// 非テンプレート関数 A<char>::f(int) を呼びます。 ac.f<>(1);// テンプレート関数 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、同等な宣言です。template<class V> V X::good(V n){return n;}   // エラー、 X の内側のどの宣言とも同等でありません。 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*();// 任意の型のポインタへの変換};   // クラス外側の定義template<typename T> A::operator T*(){return nullptr;}   // char* に対する明示的特殊化template<> A::operatorchar*(){return nullptr;}   // 明示的実体化template A::operatorvoid*();   int main(){ A a;int* ip = a.operatorint*();// 明示的な A::operator int*() の呼び出し}

オーバーロード解決において、変換関数テンプレートの特殊化は名前探索によって発見されません。 代わりに、すべての可視な変換関数テンプレートが考慮され、テンプレートの実引数推定 (変換関数テンプレートのための特別なルールがあります) によって生成されるすべての特殊化が、名前探索によって発見されたかのように使用されます。

派生クラスの using 宣言は基底クラスのテンプレート変換関数の特殊化を参照できません。

ユーザ定義変換関数テンプレートは戻り値の型を推定できません。

struct S { operator auto()const{return10;}// OKtemplate<class T> operator auto()const{return42;}// エラー};
(C++14以上)

メンバ変数テンプレート

変数テンプレートの宣言はクラススコープで行うこともできます。 この場合は静的データメンバテンプレートを宣言します。 詳細については変数テンプレートを参照してください。

(C++14以上)


[編集]欠陥報告

以下の動作変更欠陥報告は以前に発行された C++ 標準に遡って適用されました。

DR 適用先 発行時の動作 正しい動作
CWG 1878 C++14 operator auto was technically allowed operator auto forbidden
close