名前空間
変種
操作

メンバテンプレート

From cppreference.com
< cpp‎ | language
 
 
C++言語
全般
フロー制御
条件実行文
if
繰り返し文 (ループ)
for
範囲for (C++11)
ジャンプ文
関数
関数宣言
ラムダ式
inline指定子
動的例外仕様 (C++17まで*)
noexcept指定子 (C++11)
例外
名前空間
指定子
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
記憶域期間指定子
初期化
代替表現
リテラル
ブーリアン - 整数 - 浮動小数点数
文字 - 文字列 - nullptr (C++11)
ユーザー定義 (C++11)
ユーティリティ
属性 (C++11)
typedef宣言
型エイリアス宣言 (C++11)
キャスト
メモリ確保
クラス
クラス固有の関数プロパティ
explicit (C++11)
static

特殊メンバ関数
テンプレート
その他
 
 
 
 

テンプレート宣言 (クラス関数、および変数(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

囲むクラス宣言が、さらにクラステンプレートである場合、メンバテンプレートがクラス本体の外で定義されるとき、それは2組のテンプレートパラメータを取ります。1つは囲むクラス用、もう1つはそれ自身用です。

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は禁止された
English 日本語 中文(简体) 中文(繁體)