メンバテンプレート
テンプレート宣言 (クラス、関数、および変数(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は禁止された |