名前空間
変種
操作

メンバテンプレート

提供: 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*> { };       // OK
template<class T> struct A::B<T&> { };  // OK

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

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

目次

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

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

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

class Base {
    virtual void 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::operator char*() {return nullptr;}
 
// 明示的実体化
template A::operator void*();
 
int main() {
    A a;
    int* ip = a.operator int*(); // 明示的な A::operator int*() の呼び出し
}

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

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

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

struct S {
  operator auto() const { return 10; } // OK
  template<class T> operator auto() const { return 42; } // エラー
};
(C++14以上)

メンバ変数テンプレート

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

(C++14以上)


[編集] 欠陥報告

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

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