テンプレートと STL の概要

序章

テンプレートは汎用プログラミングの基礎です

以前に関数のオーバーロードを紹介しました。同じ関数名と異なるパラメーター リストを使用して多数のオーバーロードされた関数を定義して、さまざまな種類の同様の操作を実現できます。オーバーロードされた関数を呼び出すと、渡されたパラメーターに従って適切なオーバーロードされた関数が呼び出されるので、そのようなメソッドを呼び出すのに便利です。

ただし、関数のオーバーロードには依然としていくつかの欠点があります。
オーバーロードされた関数は依然として独自に定義する必要があり、コードの再利用率は高くありません。実装の種類を追加する必要がある場合、オーバーロード関数を定義する必要がありますが、オーバーロード関数の保守性は高くなく、何か問題が発生した場合はオーバーロード関数を 1 つずつ変更する必要がある場合があります。

ジェネリック プログラミングは、この問題を解決できます。すべての型に共通のコードしか記述できません。コードを使用する必要がある場合、コンパイラが対応するコードを生成します。これはコードの再利用の手段です。テンプレートは汎用プログラミングの基礎です

C++ テンプレートは、関数テンプレートとクラス テンプレートに分かれています。
ここに画像の説明を挿入

関数テンプレート

関数テンプレートは、型に関係なく、同じことを行う関数のクラスを表します。関数テンプレートは使用時にコンパイラーによって自動的にインスタンス化され、特定のタイプの関数が生成されます。

意味


template<typename T1, typename T2, ...typename Tn>
返回值 函数名(参数列表) {}
関数テンプレートを定義できます。typename はクラスに置き換えることもできます

たとえば、スワップ関数テンプレートは次のようになります。


template<typename T>
void Swap(T& a, T& b)
{
    
    
	T temp = a;
	a = b;
	b = temp;
}

その後、関数テンプレートを関数と同じように使用できます。

int main()
{
    
    
	int a = 10;
	int b = 20;
	Swap(a, b);
	cout << a << " " << b << endl;
	return 0;
}

ここに画像の説明を挿入
テンプレートによって宣言された型名は次の関数でのみ有効であることに注意してください。

インスタンス化する

関数テンプレートを使用する場合、コンパイラは、関数テンプレートのインスタンス化である、指定されたタイプの関数を生成します。

生成関数のタイプを指定する場合、暗黙的と明示的の 2 つの方法があります。

暗黙的なインスタンス化

暗黙的なインスタンス化とは、コンパイラーが呼び出し時に実際のパラメーターに従ってテンプレート パラメーターの型を自動的に指定することを意味します。
たとえば、次のコードです。

template<typename T>
T Add(const T& a, const T& b)
{
    
    
	return a + b;
}
int main()
{
    
    
	int a = 10;
	int b = 20;
	cout << Add(a, b) << endl;
	return 0;
}

ここに画像の説明を挿入
このとき、変数ab両方は int でありint、コンパイラは両方とも int であるT2 つの実パラメータから自然に型を推測できますint。これは理解するのが難しくありません。
ただし、実際のパラメータの型が異なる場合、T次の 2 つのパラメータの型のどちらであるかを判断することはできません。

	int a = 10;
	double b = 20;
	//cout << Add(a, b) << endl;  //错误代码,调用Add时模板参数不明确

ここに画像の説明を挿入
テンプレートでは、承認なしに型変換が行われることはありません。たとえばこの場合、型がTあいまいな場合、int を double に変換するか、double を int に変換するかがわかりません。

もちろん、解決策は非常に簡単です。

  1. パラメータを渡すときに、一貫性を保つために実際のパラメータの型を明示的に変換できます。
template<typename T>
T Add(const T& a, const T& b)
{
    
    
	return a + b;
}
int main()
{
    
    
	int a = 10;
	double b = 20;
	cout << Add(a, (int)b) << endl;
	return 0;
}

ここに画像の説明を挿入
型変換により一時変数が生成され、その一時変数は定数であることに注意してください。したがって、テンプレートの仮パラメータの型をconst変更しない場合、権限の増幅が発生するため、この方法はお勧めできません。

  1. もちろん、 type を明示的に指定してT、コンパイラが暗黙的な型変換、つまり明示的なインスタンス化を実行しようとすることもできます。

明示的なインスタンス化

明示的なインスタンス化とは、呼び出し時に関数名の<>後にテンプレート パラメーターの型を明示的に指定する函数名<模板参数列表>(实参列表);
ことです。たとえば、上記の [テンプレート生成関数の追加] 関数の呼び出しです。

int main()
{
    
    
	int a = 10;
	double b = 20;
	cout << Add<int>(a, b) << endl; // Add<int>(a, b)
	return 0;
}

ここに画像の説明を挿入
テンプレート パラメータの型が指定されている場合、コンパイラはパラメータを渡すときに当然ながら暗黙的な型変換を実行でき、変換が失敗した場合はエラーが報告されます。

注意しなければならないことは次のとおりです。

  1. 非テンプレート関数は、同じ名前の関数テンプレートと同時に存在できます。他の条件が同じ場合、非テンプレート関数が最初に呼び出され、呼び出し時にテンプレートからインスタンスは生成されません。より適切に一致する関数を生成できる場合、テンプレートが選択されます。

例えば:

int Add(const int& a, const int& b)
{
    
    
	return a + b;
}

template<typename T1, typename T2>
T1 Add(const T1& a, const T2& b)
{
    
    
	return a + b;
}
int main()
{
    
    
	cout << Add(1, 2) << endl;
	cout << Add(1, 2.0) << endl;
	return 0;
}

Add 関数が初めて呼び出されるとき、実際のパラメータの型は int であるため、非テンプレート関数が最初に呼び出されます。Add 関数が 2 回目に呼び出されるとき、
ここに画像の説明を挿入
最初のパラメータの型は int で、2 番目のパラメータはdouble であり、テンプレート関数によって生成された Add はより適切に一致する可能性があるため、テンプレートを呼び出します。
ここに画像の説明を挿入
3.テンプレート関数では自動型変換は許可されませんが、通常の関数は自動型変換を実行できます。

クラステンプレート

関数と同様に、型に依存しないクラス、つまりクラス テンプレートを定義することもできます。使用すると、指定されたテンプレート パラメーター タイプのクラス タイプとしてコンパイラによってインスタンス化されます。

意味


template<typename T1, typename T2, ...typename Tn>
class 类模板名 {};
関数テンプレートを定義できます。typename はクラスに置き換えることもできます

たとえば、単純なスタックを作成できます。

template<typename T>
class Stack
{
    
    
public:
	Stack(size_t size = 0, size_t capacity = 0)  //构造函数
		: _size(size)
		, _capacity(capacity)
		, _date(nullptr)
	{
    
    
		_date = new T[_capacity + 1]{
    
     0 };
	}
	void push(T n)    //压栈
	{
    
    
		if (_size == _capacity)
		{
    
    
			if (_capacity == 0)
			{
    
    
				reserve(6);
			}
			else
			{
    
    
				reserve(_capacity * 2);
			}
		}
		_date[_size] = n;
		++_size;
	}
	void reserve(size_t capacity)    
	{
    
    
		if (capacity > _capacity)
		{
    
    
			T* newdate = new T[capacity + 1]{
    
     0 };
			_capacity = capacity;
			for (int i = 0; i < _size; ++i)
			{
    
    
				newdate[i] = _date[i];
			}
			delete[] _date;
			_date = newdate;
		}
	}
	T top()
	{
    
    
		return _date[_size - 1];
	}
	size_t size()   
	{
    
    
		return _size;
	}
	~Stack()   //析构函数
	{
    
    
		delete[] _date;
		_size = 0;
		_capacity = 0;
	}
private:
	size_t _size;
	size_t _capacity;
	T* _date;
};

int型データの場合:

int main()
{
    
    
	Stack<int> nums;
	nums.push(1);
	nums.push(2);
	nums.push(3);
	nums.push(4);
	nums.push(5);
	cout << nums.top() << endl;
	cout << nums.size() << endl;
	return 0;
}

ここに画像の説明を挿入
char型データの場合:

int main()
{
    
    
	Stack<char> str;
	str.push('a');
	str.push('b');
	str.push('c');
	str.push('d');
	str.push('e');
	cout << str.top() << endl;
	cout << str.size() << endl;
	return 0;
}

ここに画像の説明を挿入
さまざまなテンプレート パラメーター タイプに対して、この単純なスタックが効果を発揮できることを見つけるのは難しくありません。

インスタンス化する

関数テンプレートとは異なり、クラス テンプレートはパラメーターを通じてテンプレート パラメーターの型を推測できないため、クラス テンプレートのインスタンス化では、<>呼び出し後にクラス テンプレート名でテンプレート パラメーターを明示的に示す必要があります。

上記のスタック テンプレートの使用例:

int main()
{
    
    
	//实例化类模板并实例化类对象
	Stack<char> str;
	Stack<int> nums;
	Stack<double> dnums;

	//对不同类型的栈堆栈
	str.push('a');
	str.push('b');
	nums.push(3);
	nums.push(4);
	dnums.push(20.0);
	dnums.push(30.0);

	//打印不同类型栈的栈顶元素及元素个数
	cout << str.top() << endl;
	cout << str.size() << endl;
	cout << nums.top() << endl;
	cout << nums.size() << endl;
	cout << dnums.top() << endl;
	cout << dnums.size() << endl;
	return 0;
}

ここに画像の説明を挿入

クラステンプレートの名前は実際のクラスではありませんが、インスタンス化の結果が実際のクラスであることに注意してください。

STL の概要

STL (標準テンプレート ライブラリ - 標準テンプレート ライブラリ): C++ 標準ライブラリの重要な部分であり、再利用可能なコンポーネント ライブラリであるだけでなく、データ構造とアルゴリズムを含むソフトウェア フレームワークでもあります。

STL 6 つの主要コンポーネント

ここに画像の説明を挿入
コンテナ: 文字列、ベクトル、リスト、デキュー、マップ、セットなど。
アルゴリズム: 検索、交換、逆順、並べ替えなど。

(これは理解のためのものであり、後で徐々に詳しく紹介します)

要約する


この時点で、関数テンプレートやクラス テンプレートを含む、テンプレートの初期コンテンツの導入は終了です。

この部分を明確に紹介していない、またはこの部分に問題があると思われる場合は、コメント欄に指摘してください。

この記事が少しでもお役に立てましたら、ワンクリックでつながれば幸いです

皆さんと一緒に進歩していきたいと思っています

おすすめ

転載: blog.csdn.net/weixin_73450183/article/details/131139199