序文
最近STLソースコード分析を見ていたときに、typenameの使用法に遭遇しました。通常、テンプレートパラメータを定義するときにのみ接触しました。この問題が発生するまで、typenameの使用法を徹底的に検索しました。次の例を見てみましょう。
typedef typename iterator_traits<_Iter>::value_type value _type;
typedef、つまり、typedef +元の型名+新しい型名の形式でエイリアスを定義することはよく知っているかもしれません。したがって、typename
iterator_traits <_Iter> :: value_typeが型名であることがわかりますが、それは何ですか。混乱しているのは、なぜここで必要なのですか?typenameキーワードを使用しますか?
typenameの従来の使用法
typenameは、C ++クラステンプレートまたは関数テンプレートで頻繁に使用されるキーワードです。この時点で、関数は、テンプレートパラメータが定義されていることを除いて、クラスと同じです。次の例では、関数は一般的な交換データ、つまり交換を実装します。 2つのデータの内容、dataタイプは_Tpによって決定されます。
template <typename _Tp>
inline void swap(_Tp& __a, _Tp& __b)
{
_Tp __tmp = __a;
__a = __b;
__b = __tmp;
}
typenameの2番目の使用法:変更されたタイプ
2番目の使用法を紹介する前に、まずいくつかの基本的な概念を理解してください。
修飾名と非修飾名
修飾名は、名前空間を定義する名前です。次のコードを見てください。coutとendlは名前空間stdで定義されています。std:: coutとstd :: endlにするには、std ::を追加する必要があるため、修飾名と呼ばれます。
#include <iostream>
int main()
{
std::cout << "Hello world!" << std::endl;
}
main関数の前にnamespacestdを使用するか、main関数で
std :: cout;を使用する場合は、それらを使用するときにのみcoutとendlを使用します。std::を制限するためにそれらの前にスペースはありません。したがって、coutとendlは非修飾
名と呼ばれます。
#include <iostream>
using namespace std;
int main()
{
//using std::cout;
//using std::endl;
cout << "Hello world!" << endl;
}
依存名と非依存名
依存名(依存名)はテンプレートパラメーターに依存する名前を指し、非依存
名(非依存名)はその逆で、テンプレートパラメーターに依存しない名前を指します。次のコードを見てください。
template <class T>
class MyClass {
int i;
vector<int> vi;
vector<int>::iterator vitr;
T t;
vector<T> vt;
vector<T>::iterator viter;
};
intは組み込み型であるため、テンプレートクラスが宣言されるときに、最初の3つの定義された型が認識され、それらは非依存名と呼ばれます。ただし、次の3行の定義では、それらはすべてテンプレートパラメータTに依存しているため、テンプレートがインスタンス化されたときにのみタイプを知ることができます。その場合、T、
vector <T>、vector <T> :: iteratorは従属名と呼ばれます。
クラススコープ
クラス外のクラスの名前にアクセスするときは、クラススコープ演算子を使用できます。通常、呼び出しには、静的データメンバー、静的メンバー関数、ネストされたタイプの3つのタイプがあります:Mydata :: value、Mydata :: function、Mydata :: str;
class Mydata {
static int value;
static int function();
typedef string str;
};
例を見てみましょう:
template <class T>
void function()
{
T::iterator *iter;
.....
}
上記の例を見ると、2つのアイデアが思い浮かぶかもしれません。1つ目:T :: iterator * iter;乗算を実現するには、イテレーターはクラスTのメンバーです。2つ目:ポインターを定義します。ポインターが指す型は次のとおりです。 T ::イテレータ;
この場合、異論があります。上記の紹介から、イテレータはクラスTの静的データメンバー、静的メンバー関数、またはネストされた型であることがわかります。キーワードtypenameが変更されていない場合、コンパイラは次のように考える可能性があります。乗算を実装したい場合;ポインタを定義する場合、ポインタをtypenameで変更する必要がある、つまり、T :: iteratorの前にキーワードtypenameを追加する必要がある場合。
template <class T>
class myData()
{
typename T::iterator *iter;//定义一个指针
typedef typename iterator_traits<_Iter>::value_type value _type;//定义一个别名
.....
};
タイプ名の使用規則
次の状況では、typenameの使用は禁止されています。
- テンプレート定義の外部、つまり、typenameはテンプレートの定義でのみ使用できます
- int、vector <int>などの非修飾型。
- テンプレート<classT>クラスC1などの基本クラスリスト:T :: InnerTypeはT :: InnerTypeの前にtypenameを追加できません
- コンストラクターの初期化リスト内
タイプがテンプレートパラメータに依存する修飾名である場合、typenameをその前に追加する必要があります(基本クラスのリストまたはクラスの初期化されたメンバーのリストでない限り)。
Matlab、Python、C ++でのプログラミング、機械学習、コンピュータービジョン理論の実装とガイダンス、学部と修士の両方の学位、塩漬け魚の取引、専門家の回答をご覧ください。詳細については、QQ番号757160542にお問い合わせください。