可能重複:
正式にtypenameは何ですか?
テンプレートをどこに置く必要があるのですか? typenameのキーワードは?
以下のコードを検討してください:
template
class C {
struct P {};
vector vec;
void f();
};
template void C::f() {
typename vector::iterator p = vec.begin();
}
この例で「typename」キーワードが必要な理由は何ですか? 「typename」を指定する必要がある場合は他にもありますか?
短い答え:名前が従属名のネストされた名前を参照するときはいつでも、パラメータが未知のテンプレートインスタンスの中に入れ子になっています。
長い答え:C ++には、値、型、テンプレートという3つのエンティティがあります。それらのすべてが名前を持つことができます。名前だけではエンティティのどの階層であるかは分かりません。むしろ、名前の実体の性質に関する情報は、文脈から推論されなければならない。
この推論が不可能なときはいつでも、それを指定する必要があります:
template struct Magic;//defined somewhere else
template struct A
{
static const int value = Magic::gnarl;//assumed "value"
typedef typename Magic::brugh my_type;//decreed "type"
// ^^^^^^^^
void foo() {
Magic::template kwpq(1, 'a', .5);//decreed "template"
// ^^^^^^^^
}
};
Here the names Magic
, Magic
and Magic
had to be expliciated, because it is impossible to tell: Since Magic
is a template, the very nature of the type Magic
depends on T
-- there may be specializations which are entirely different from the primary template, for example.
What makes Magic
a dependent name is the fact that we're inside a template definition, where T
is unknown. Had we used Magic
, this would be different, since the compiler knows (you promise!) the full definition of Magic
.
(これを自分でテストしたい場合は、使用できる Magic
のサンプル定義を次に示します。簡潔にするためにspecializeで constexpr
を使用してください。コンパイラは、静的メンバ定数の宣言を古いスタイルのpre-C ++ 11フォームに自由に変更することができます。)
template struct Magic
{
static const T gnarl;
typedef T & brugh;
template static void kwpq(int, char, double) { T x; }
};
template <> struct Magic
{
//note that `gnarl` is absent
static constexpr long double brugh = 0.25; //`brugh` is now a value
template static int kwpq(int a, int b) { return a + b; }
};
使用法:
int main()
{
A a;
a.foo();
return Magic::kwpq(2, 3); //no disambiguation here!
}
iterator
は P
の依存型なので、 typename
キーワードが必要です。コンパイラは、 iterator
が値または型を参照しているかどうかを推測することはできませんので、 typename
テンプレートの引数に依存する型がある場合は常に、型または値が有効であるコンテキストで必要です。たとえば、基底クラスは型でなければならないので、基底クラス typename
は不要です。
同じ主題では、 template
というキーワードがあります。これは、依存名が値ではなくテンプレート関数であることをコンパイラに知らせるためです。
typenameキーワードは、型名がテンプレートパラメータに依存する場合に必要です(コンパイラは識別子の意味( type または value )最初のパスで完全なシンボルテーブル)。
Not in the same meaning, and a bit less common, the lone typename keyword can also be useful when using generic template parameters: http://ideone.com/amImX
#include
#include
#include
template class Container,
template class Alloc = std::allocator>
struct ContainerTests
{
typedef Container > IntContainer;
typedef Container > StringContainer;
//
void DoTests()
{
IntContainer ints;
StringContainer strings;
//... etc
}
};
int main()
{
ContainerTests t1;
ContainerTests t2;
t1.DoTests();
t2.DoTests();
}