typename
dan class
dapat dipertukarkan dalam kasus dasar menentukan templat:
template<class T>
class Foo
{
};
dan
template<typename T>
class Foo
{
};
adalah setara.
Karena itu, ada kasus khusus di mana ada perbedaan antara typename
dan class
.
Yang pertama adalah dalam kasus tipe dependen. typename
digunakan untuk mendeklarasikan saat Anda mereferensikan tipe bersarang yang bergantung pada parameter templat lain, seperti typedef
dalam contoh ini:
template<typename param_t>
class Foo
{
typedef typename param_t::baz sub_t;
};
Pertanyaan kedua yang sebenarnya Anda tunjukkan dalam pertanyaan Anda, meskipun Anda mungkin tidak menyadarinya:
template < template < typename, typename > class Container, typename Type >
Saat menentukan templat templat , class
kata kunci HARUS digunakan seperti di atas - tidak dapat dipertukarkan dengan typename
kasus ini (catatan: karena C ++ 17 kedua kata kunci diizinkan dalam kasus ini) .
Anda juga harus menggunakan class
ketika secara eksplisit membuat template:
template class Foo<int>;
Saya yakin ada beberapa kasus lain yang saya lewatkan, tetapi intinya adalah: dua kata kunci ini tidak setara, dan ini adalah beberapa kasus umum di mana Anda harus menggunakan satu atau yang lain.
template <typename T> typename Foo {};
, karena Foo <T> jelas merupakan kelas.std::vector<int>::value_type
bukan tipe dependen, Anda tidak perlu ditypename
sana - Anda hanya memerlukannya jika tipe bergantung pada parameter templat, katakanlahtemplate<class T> struct C { typedef typename std::vector<T>::value_type type; };
param_t
bukan tipe dependen. Tipe dependen adalah nama yang bergantung pada parameter templat , misalnyafoo<param_t>::some_type
, bukan parameter templat itu sendiri.typename
, yaitutemplate <typename> typename C
.GCC 5
, G ++ sekarang memungkinkan nama ketik dalam parameter templat templat .Untuk parameter penamaan template,
typename
danclass
setara. §14.1.2:typename
namun dimungkinkan dalam konteks lain saat menggunakan template - untuk memberi petunjuk pada kompiler bahwa Anda merujuk pada tipe dependen. §14.6.2:Contoh:
Tanpa
typename
kompiler tidak dapat memberi tahu secara umum apakah Anda merujuk pada suatu tipe atau tidak.sumber
Meskipun tidak ada perbedaan teknis, saya telah melihat keduanya digunakan untuk menunjukkan hal-hal yang sedikit berbeda.
Untuk templat yang menerima jenis apa pun sebagai T, termasuk bawaan (seperti larik)
Untuk templat yang hanya akan berfungsi jika T adalah kelas nyata.
Namun perlu diingat bahwa ini adalah murni gaya yang digunakan sebagian orang. Tidak diamanatkan oleh standar atau dipaksakan oleh kompiler
sumber
T t; int i = t.toInt();
) maka Anda memerlukan "kelas nyata", dan kode Anda tidak dapat dikompilasi jika Anda menyediakanint
untukT
...class
menyiratkan bahwa Anda tidak hanya mengharapkan "nilai" yang mungkin mendukung beberapa operator, menyalin atau memindahkan konstruksi dan / atau penugasan, tetapi secara khusus membutuhkan jenis yang mendukung beberapa semantik akses anggota. Pandangan tercepat pada deklarasi kemudian menetapkan harapan dan patah semangat misalnya memasok tipeclass
bawaan untuk parameter ketika itu pasti akan menjadi kesalahan.Container
sendiri merupakan templat dengan dua jenis parameter.sumber
template<template<class U> class V> struct C {};
Cuplikan ini dari c ++ buku utama. Meskipun saya yakin ini salah.
Setiap parameter tipe harus didahului oleh kelas kata kunci atau nama ketik:
Kata kunci ini memiliki arti yang sama dan dapat digunakan secara bergantian di dalam daftar parameter template. Daftar parameter templat dapat menggunakan kedua kata kunci:
Tampaknya lebih intuitif untuk menggunakan nama kunci kata kunci daripada kelas untuk menetapkan parameter jenis template. Lagi pula, kita bisa menggunakan tipe bawaan (bukan kelas) sebagai argumen tipe templat. Selain itu, nama ketik lebih jelas menunjukkan bahwa nama yang mengikuti adalah nama jenis. Namun, nama ketik ditambahkan ke C ++ setelah templat sudah digunakan secara luas; beberapa programmer terus menggunakan kelas secara eksklusif
sumber