perhatikan kode di bawah ini:
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();
}
Mengapa "typename" kata kunci yang diperlukan dalam contoh ini? Apakah ada kasus lain di mana "typename" harus ditentukan?
Jawaban singkat: Bila mengacu pada bersarang nama tergantung nama, yaitu bersarang di dalam template contoh dengan parameter yang tidak diketahui.
Jawaban panjang: Ada tiga tingkatan entitas dalam C++: nilai-nilai, jenis, dan template. Semua orang dapat memiliki nama, dan nama saja doesn't memberitahu anda yang tier entitas itu. Sebaliknya, informasi mengenai sifat dari sebuah nama's entitas harus disimpulkan dari konteks.
Setiap kali inferensi ini tidak mungkin, anda harus menentukan:
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"
// ^^^^^^^^
}
};
Berikut nama-nama Magic<T>::gnarl
, Sihir<T>::brugh
dan Sihir<T>::kwpq
harus expliciated, karena itu adalah mustahil untuk mengatakan: Sejak Sihir
adalah template, sangat alam jenis Sihir<T>
tergantung pada T
-- mungkin ada spesialisasi yang sama sekali berbeda dari template utama, misalnya.
Apa yang membuat Magic<T>::gnarl
tergantung nama adalah kenyataan bahwa kita're dalam definisi template, di mana T
yang tidak diketahui. Kalau kita menggunakan Magic<int>
, ini akan berbeda, karena compiler tahu (kau janji!) definisi lengkap dari Sihir<int>
.
(Jika anda ingin menguji diri sendiri, di sini's contoh definisi dari Sihir
yang dapat anda gunakan. Maafkan penggunaan constexpr
di specializaation untuk singkatnya, jika anda memiliki tua compiler, merasa bebas untuk mengubah anggota statis konstan deklarasi tua-gaya pra-C++11 bentuk.)
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; }
};
Penggunaan:
int main()
{
A<int> a;
a.foo();
return Magic<signed char>::kwpq<float>(2, 3); // no disambiguation here!
}
The typename
kata kunci, diperlukan karena iterator
adalah jenis tergantung pada P
. Compiler dapat't menebak jika iterator
mengacu pada nilai atau tipe, sehingga mengasumsikan nilai kecuali jika anda berteriak typename
. It's diperlukan setiap kali ada jenis tergantung pada template argumen, dalam konteks yang baik jenis atau nilai-nilai yang akan berlaku. Misalnya, sebagai dasar kelas typename
tidak diperlukan sejak kelas dasar harus tipe.
Pada subjek yang sama, ada template
kata kunci yang digunakan untuk memberitahu compiler tahu bahwa tergantung beberapa nama adalah template fungsi alih dari suatu nilai.
Yang typename kata kunci diperlukan setiap kali nama jenis tergantung pada parameter template, (sehingga penyusun dapat 'tahu' semantik dari sebuah identifier (ketik atau nilai) tanpa harus penuh simbol tabel pada lulus pertama).
Tidak dalam arti yang sama, dan sedikit kurang umum, lone typename keyword juga dapat berguna ketika menggunakan generic parameter template: 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();
}