エイリアス テンプレートとテンプレート パラメータ

今日は、エイリアス テンプレートとテンプレート パラメーターという 2 つのトピックについて書きます。エイリアス テンプレートは、型のファミリに名前を付ける方法です。テンプレート パラメーターは、型、非型、およびテンプレート自体にすることができます。

エイリアス テンプレートから始めましょう。

エイリアス テンプレート

C++11 では、エイリアス テンプレートが用意されています。エイリアス テンプレートは、型のファミリに便利な名前を付ける手段を提供します。次のコード スニペットは、クラス テンプレート Matrix のアイデアを示しています。

template <typename T, int Line, int Col>
class Matrix{
 ....
};

Matrix には 3 つのテンプレート パラメータがあります。型パラメータ T 、および非型パラメータ Line 、および Col (テンプレート パラメーターについては、次のセクションで説明します。)

読みやすくするために、2 つの特別な行列が必要です:Square そして Vector . Square の行数と列数は等しくなければなりません。 Vector の行サイズは 1 にする必要があります。型エイリアスのおかげで、自分のアイデアをコードで直接表現できます。

template <typename T, int Line>
using Square = Matrix<T, Line, Line>; // (1)

template <typename T, int Line>
using Vector = Matrix<T, Line, 1>; // (2)

キーワード using ((1) and (2)) は型エイリアスを宣言します。プライマリ テンプレート Matrix 三次元 T でパラメータ化できます 、 Line 、および Col 、型エイリアス SquareVector パラメータ化を 2 次元に減らします TLine .この観点から、エイリアス テンプレートを使用すると、部分的にバインドされたテンプレートの直感的な名前を作成できます。 Square の使用 と Vector

Matrix<int, 5, 3> ma;
Square<double, 4> sq;
Vector<char, 5> vec;

エイリアス テンプレートの優れた使用例は、type-traits ライブラリです。

型特性ライブラリ

std::move(arg)を適用すると 値 arg 、コンパイラは通常 std::remove_reference を使用します 基になる型から参照を削除するには:

static_cast<std::remove_reference<decltype(arg)>::type&&>(arg); // (1)

static_cast<std::remove_reference_t<decltype(arg)>&&>(arg); // (2)

エイリアス テンプレートのおかげで、バージョン (2 行目) は C++14 以降で有効です。次のヘルパー タイプが利用可能です:

template< class T >
using remove_reference_t = typename remove_reference<T>::type;

もちろん、型を返す type-traits ライブラリの他の関数に対応するヘルパー型も C++14 で利用できます。

以前に定義されたクラス テンプレート Matrix 2 つの非型テンプレート パラメータ Line を使用します と Col .

テンプレート パラメータ

テンプレート パラメーターは、型、非型、およびテンプレート自体にすることができます。

タイプ

さて、型は最も頻繁に使用されるテンプレート パラメーターです。以下にいくつかの例を示します:

std::vector<int> myVec;
std::map<std::string, int> myMap;
std::lock_guard<std::mutex> myLockGuard;

非型

非型は

  • 左辺値参照
  • nullptr
  • ポインタ
  • enum の列挙子
  • 整数値
  • 浮動小数点値 (C++20)

整数値は、最も使用される非型です。 std::array は、コンパイル時に std::array のサイズを指定する必要があるため、典型的な例です:

std::array<int, 3> myArray{1, 2, 3};

テンプレート

テンプレート自体をテンプレート パラメータにすることができます。それらの定義は少し奇妙に見えるかもしれません。

// templateTemplateParameters.cpp

#include <iostream>
#include <list>
#include <vector>
#include <string>

template <typename T, template <typename, typename> class Cont > // (1)
class Matrix{
public:
 explicit Matrix(std::initializer_list<T> inList): data(inList) { // (2)
 for (auto d: data) std::cout << d << " ";
 }
 int getSize() const{
 return data.size();
 }

private:
 Cont<T, std::allocator<T>> data; // (3) 

};

int main(){

 std::cout << '\n';

 // (4)
 Matrix<int, std::vector> myIntVec{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 
 std::cout << '\n';
 std::cout << "myIntVec.getSize(): " << myIntVec.getSize() << '\n';

 std::cout << std::endl;

 Matrix<double, std::vector> myDoubleVec{1.1, 2.2, 3.3, 4.4, 5.5}; // (5)
 std::cout << '\n';
 std::cout << "myDoubleVec.getSize(): " << myDoubleVec.getSize() << '\n';

 std::cout << '\n';
 // (6)
 Matrix<std::string, std::list> myStringList{"one", "two", "three", "four"}; 
 std::cout << '\n';
 std::cout << "myStringList.getSize(): " << myStringList.getSize() << '\n';

 std::cout << '\n';

}

Matrix std::initializer_list (2 行目) で初期化できる単純なクラス テンプレートです。 Matrix は、std::vector (4 行目と 5 行目) または std::list (6 行目) と共に使用して、その値を保持できます。これまでのところ、特別なことは何もありません。

ただし、1 行目と 3 行目に言及するのを忘れています。1 行目では、2 つのテンプレート パラメーターを持つクラス テンプレートを宣言しています。最初のパラメーターは要素の型で、2 番目のパラメーターはコンテナーを表します。 2 番目のパラメーターを詳しく見てみましょう:template class Cont>。これは、2 番目のテンプレート引数が 2 つのテンプレート パラメーターを必要とするテンプレートであることを意味します。最初のテンプレート パラメーターはコンテナーが格納する要素の型で、2 番目のテンプレート パラメーターは標準テンプレート ライブラリのコンテナーが持つ既定のアロケーターです。 std::vector の場合のように、アロケータにもデフォルト値があります。アロケータは要素のタイプによって異なります。

template<
 class T,
 class Allocator = std::allocator<T>
> class vector;

3 行目は、この内部的に使用されるコンテナーでのアロケーターの使用法を示しています。マトリックスは、コンテナ <要素の型、要素のアロケータ> の種類のすべてのコンテナを使用できます。これは、std::vector、std::deque、または std::list などのシーケンス コンテナーに当てはまります。 std::array と std::forward_list は失敗します。これは、std::array がコンパイル時にサイズを指定するために追加の非型が必要であり、std::forward_list が size メソッドをサポートしていないためです。

テンプレート テンプレート パラメータの名前のキーワード class が気に入らない場合があります。 C++17 では、class を置き換えることができます typename で :

template <typename T, template <typename, typename> class Cont > // (1)
class Matrix;

template <typename T, template <typename, typename> typename Cont > // (2) 
class Matrix;

行 (2) は C++17 以降で有効であり、行 (1) と同等です。

次の pdf バンドル:コルーチン

投稿では、「どの pdf バンドルが必要ですか? 選択してください!」コルーチン バンドルを決定しました。

私はまだバンドルを準備中ですが、数日中に利用可能になるはずです。

英語のニュースレターを購読すると、最新の pdf バンドルへのリンクが自動的に取得されます。このページの右上隅を見てください。この自動化は、私にとって非常に快適です。私のニュースレターを既に購読している人は、リンクを自動的に取得します。

次は?

次の投稿では、テンプレートの引数について書きます。コンパイラが型を推測する方法は非常に興味深いものです。ルールは関数テンプレート (C++98) だけでなく、auto にも適用されます。 (C++11)、クラス テンプレート (C++17)、概念 (C++20) へ。