Namespaces
Variants

Member templates

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

テンプレート宣言 ( class , function , および variables (C++14以降) ) は、 member specification 内に現れることができます。これは、 local classes ではない任意のクラス、構造体、または共用体に適用されます。

#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
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::ranges::for_each(s, 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*> {};      // CWG 727経由でOK: 完全特殊化
};
template<> struct A::B<int*> {};       // OK
template<class T> struct A::B<T&> {};  // OK

外側のクラス宣言がクラステンプレートである場合、メンバーテンプレートをクラス本体の外側で定義するとき、2組のテンプレートパラメータを取ります:1つは外側のクラスのため、もう1つは自身のためのものです:

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) { /* ... */ }

目次

メンバー関数テンプレート

Destructor copy constructor はテンプレートにできません。copy constructorの型シグネチャでインスタンス化可能なテンプレートコンストラクタが宣言されている場合、 implicitly-declared copy constructor が代わりに使用されます。

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

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>(char) を呼び出す
    ac.f(1);   // 非テンプレート関数 A<char>::f(int) を呼び出す
    ac.f<>(1); // テンプレート関数 A<char>::f<int>(int) を呼び出す
}


メンバー関数テンプレートのクラス外定義は、クラス内の宣言と 等価 でなければなりません(等価性の定義については function template overloading を参照)。そうでない場合、オーバーロードとして扱われます。

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内部のどの宣言とも等価ではない
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*() の明示的呼び出し
}

overload resolution の間、 name lookup によって変換関数テンプレートの特殊化は見つかりません。代わりに、可視の変換関数テンプレートがすべて考慮され、 template argument deduction (変換関数テンプレートには特別なルールがあります)によって生成されるすべての特殊化が、name lookup によって見つかったかのように使用されます。

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

ユーザー定義変換関数テンプレートは推論された戻り値の型を持つことはできません:

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

メンバ変数テンプレート

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

(C++14以降)

不具合報告

以下の動作変更の欠陥報告書は、以前に公開されたC++規格に対して遡及的に適用されました。

DR Applied to Behavior as published Correct behavior
CWG 1878 C++14 operator auto が技術的に許可されていた operator auto を禁止