可能性のある複製:
正式には、typenameは何のためですか?
テンプレートとtypenameキーワードをどこに、なぜ配置する必要があるのですか?
以下のコードを検討してください。
template<class K>
class C {
struct P {};
vector<P> vec;
void f();
};
template<class K> void C<K>::f() {
typename vector<P>::iterator p = vec.begin();
}
この例で「typename」キーワードが必要なのはなぜですか? 「typename」を指定する必要がある他のケースはありますか?
簡単な答え:従属名であるネストされた名前を参照するときは常に、つまり、未知のパラメーターを持つテンプレートインスタンス内にネストされます。
長い答え:C++には、値、型、およびテンプレートの3つの層のエンティティがあります。それらはすべて名前を持つことができ、名前だけではどの層のエンティティかはわかりません。むしろ、名前のエンティティの性質に関する情報は、コンテキストから推測する必要があります。
この推論が不可能な場合は、必ず指定する必要があります。
template <typename> struct Magic; // defined somewhere else
template <typename T> struct A
{
static const int value = Magic<T>::gnarl; // assumed "value"
typedef typename Magic<T>::brugh my_type; // decreed "type"
// ^^^^^^^^
void foo() {
Magic<T>::template kwpq<T>(1, 'a', .5); // decreed "template"
// ^^^^^^^^
}
};
ここでは、Magic<T>::gnarl
、Magic<T>::brugh
、およびMagic<T>::kwpq
の名前を明示する必要がありました。これは、伝えることが不可能なためです。Magic
はテンプレートであるため、非常にタイプ_natureの性質Magic<T>
はT
に依存します-たとえば、プライマリテンプレートとはまったく異なる特殊化が存在する場合があります。
Magic<T>::gnarl
を従属名にしているのは、T
が不明なテンプレート定義内にいるという事実です。 Magic<int>
を使用した場合、コンパイラはMagic<int>
の完全な定義を知っているので(お約束します!)、これは異なります。
(これを自分でテストしたい場合は、使用できるMagic
のサンプル定義を以下に示します。簡潔にするためにconstexpr
を使用することはご容赦ください。古いコンパイラをお持ちの場合は、お気軽に変更してください。古いスタイルのC++ 11以前の形式への静的メンバー定数宣言。)
template <typename T> struct Magic
{
static const T gnarl;
typedef T & brugh;
template <typename S> static void kwpq(int, char, double) { T x; }
};
template <> struct Magic<signed char>
{
// note that `gnarl` is absent
static constexpr long double brugh = 0.25; // `brugh` is now a value
template <typename S> static int kwpq(int a, int b) { return a + b; }
};
使用法:
int main()
{
A<int> a;
a.foo();
return Magic<signed char>::kwpq<float>(2, 3); // no disambiguation here!
}
typename
はiterator
の依存型であるため、P
キーワードが必要です。コンパイラは、iterator
が値または型を参照しているかどうかを推測できないため、typename
を叫ばない限り、その値を想定します。型または値のいずれかが有効であるコンテキストで、テンプレート引数に依存する型がある場合は常に必要です。たとえば、基底クラスは型でなければならないため、基底クラスtypename
は必要ありません。
同じテーマで、いくつかの依存名が値ではなくテンプレート関数であることをコンパイラーに知らせるために使用されるtemplate
キーワードがあります。
Typenameキーワードは、型名がテンプレートパラメーターに依存する場合に必要です(したがって、コンパイラーは識別子のセマンティクスを「知る」ことができます(typeまたはvalue)最初のパスで完全なシンボルテーブルを持たない)。
同じ意味ではなく、少し一般的ではありませんが、lone typenameキーワードは、汎用テンプレートパラメータを使用する場合にも役立ちます。 http: //ideone.com/amImX
#include <string>
#include <list>
#include <vector>
template <template <typename, typename> class Container,
template <typename> class Alloc = std::allocator>
struct ContainerTests
{
typedef Container<int, Alloc<int> > IntContainer;
typedef Container<std::string, Alloc<int> > StringContainer;
//
void DoTests()
{
IntContainer ints;
StringContainer strings;
// ... etc
}
};
int main()
{
ContainerTests<std::vector> t1;
ContainerTests<std::list> t2;
t1.DoTests();
t2.DoTests();
}