Şablonlarda 'typename' ve 'class' anahtar kelimelerinin farkı nedir?


504

Şablonlar için her iki bildirimi de gördüm:

template < typename T >
template < class T >

Fark ne?

Ve aşağıdaki örnekte bu anahtar kelimeler tam olarak ne anlama geliyor (şablonlar hakkındaki Alman Wikipedia makalesinden alınmıştır)?

template < template < typename, typename > class Container, typename Type >
class Example
{
     Container< Type, std::allocator < Type > > baz;
};

Yanıtlar:


430

typenameve classbir şablon belirtmenin temel durumunda değiştirilebilir:

template<class T>
class Foo
{
};

ve

template<typename T>
class Foo
{
};

eşdeğerdir.

Bunu söyledikten sonra, typenameve arasındaki farkın olduğu belirli durumlar vardır.class .

Birincisi bağımlı tipler söz konusudur. typename, typedefbu örnekte olduğu gibi başka bir şablon parametresine bağlı iç içe bir türe başvururken bildirmek için kullanılır :

template<typename param_t>
class Foo
{
    typedef typename param_t::baz sub_t;
};

Sorunuzda gerçekten gösterdiğiniz ikincisi, bunun farkında olmasanız da:

template < template < typename, typename > class Container, typename Type >

Bir belirtirken şablon şablonu , classanahtar kelime yukarıda gibi kullanılmalıdır - öyle değil ile değiştirilebilir typenamebu durumda (not: Her iki anahtar kelimeler bu durumda izin verilen C ++ 17 beri) .

classBir şablonu açıkça başlatırken de kullanmalısınız :

template class Foo<int>;

Kaçırdığım diğer durumlar olduğundan eminim, ancak sonuçta: bu iki anahtar kelime eşdeğer değildir ve bunlar, birini veya diğerini kullanmanız gereken bazı yaygın durumlardır.


45
Bu sonuncusu, bir sınıfı tanımlamak için sınıf adı değil sınıf veya yapı kullanmanız gerektiğinin neredeyse özel bir örneğidir. Açıkçası, ilk iki kod parçanızın hiçbiri ile değiştirilemez template <typename T> typename Foo {};, çünkü Foo <T> kesinlikle bir sınıftır.
Steve Jessop

2
std::vector<int>::value_typebağımlı bir tür değil, typenameoraya ihtiyacınız yok - sadece bir tür bir şablon parametresine bağlıysa buna ihtiyacınız var, diyelimtemplate<class T> struct C { typedef typename std::vector<T>::value_type type; };
Georg Fritzsche

2
Ve yine, param_tbağımlı bir tür değil. Bağımlı türler, şablon parametresine bağımlı olan adlardır , örneğin foo<param_t>::some_typeşablon parametrelerinin kendileri değil.
Georg Fritzsche

2
Bir C ++ 1z öneri N4051 kullanmak sağlayacak typename, yani template <typename> typename C.
user4112979

4
İtibarıyla GCC 5, G ++ artık şablon, şablon parametresinde TypeName sağlar .
Chnossos

95

Şablon parametrelerini adlandırmak için typenameve classeşdeğerdir. §14.1.2:

Şablon parametresinde sınıf ve tür adı arasında anlamsal bir fark yoktur.

typenameancak şablonları kullanırken başka bir bağlamda mümkündür - derleyiciye bağımlı bir türe başvurduğunuzu belirtmek için. §14.6.2:

Bir şablon bildiriminde veya tanımında kullanılan ve bir şablon parametresine bağlı olan bir ad, geçerli ad araması bir tür adı bulamazsa veya ad, tür anahtar sözcüğü tarafından nitelendirilmedikçe, bir tür adlandırmayacağı varsayılır.

Misal:

typename some_template<T>::some_type

Olmadan typenamederleyici bir tip atıfta olsun ya da olmasın, genel olarak söyleyemem.


2
Kuralı anlıyorum, ancak derleyicinin some_template <T> içine dahili olarak bir tür olarak davranmasını tam olarak engelleyen nedir? Açık bir şeyi kaçırırsam özür dilerim.
batbrat

23

Teknik bir fark olmamakla birlikte, ikisinin biraz farklı şeyler ifade ettiğini gördüm.

Yerleşik öğeler (dizi gibi) dahil olmak üzere T olarak herhangi bir türü kabul etmesi gereken bir şablon için

template<typename T>
class Foo { ... }

Yalnızca T'nin gerçek bir sınıf olduğu yerde çalışacak bir şablon için.

template<class T>
class Foo { ... }

Ancak bunun yalnızca bazı kişilerin kullandığı stil tarzı bir şey olduğunu unutmayın. Standart tarafından zorunlu kılınmamış veya derleyiciler tarafından zorunlu kılınmamıştır


15
Bahsettiğin için seni suçlamıyorum, ama bence bu politika oldukça yanlış yönlendirilmiş, çünkü programcılar önemli olmayan bir şeyi düşünmek için zaman ayırıyor ("doğru olanı kullandım mı?"). t matter ("bu şablon parametresinin gerektirdiği arabirimi uygulayan yerleşik bir tür var mı?"). Şablon parametresi herhangi bir üyesi (kullanılırsa T t; int i = t.toInt();o zaman) bir "gerçek sınıf" gerekir ve tedarik eğer kod derlemek olmaz intiçin T...
Steve Jessop

1
Kullanımın gerçek sınıflarla sınırlandırılmasını istiyorsanız, sınıf dışı türler için hata / hataya neden olacak bir uzmanlık eklemeniz daha iyi olur. Belirli sınıflarla kullanımı sınırlamak istiyorsanız, sadece onlar için uzmanlaşın. Her durumda, böyle bir stilistik ayrım mesajı iletmek için çok incedir.
Potatoswatter

2
Aynı anlama geldikleri için lütfen sadece bir tane kullanın. Aksi takdirde, satır içi {, Salı değilse ve sonraki satırı {kullanıyorsunuz.
Paul Draper

+1 Bunu bazen kendim yaparım ... classsadece bazı operatörleri destekleme, inşaat ve / veya atamayı kopyalama veya taşıma gibi bir "değer" beklemediğiniz anlamına gelir, ancak özellikle bazı üye erişim semantiğini destekleyen bir türe ihtiyaç duyarsınız. Deklarasyona en hızlı bakış, beklentiler ve cesaretleri belirler; örneğin class, bu kesinlikle bir hata olduğunda parametreler için yerleşik tiplerin sağlanması .
Tony Delroy

Bir şablonun HERHANGİ BİR sınıf için işe yarayacağı, ancak yerleşik türlerle çalışmadığı yerlerde ne tür gerçek dünya durumlarının var olduğunu anlamak istiyorum. Bir örnek var mı?
lfalin

7
  1. Fark yok
  2. Şablon türü parametresinin Containerkendisi iki tür parametresine sahip bir şablondur.

3
genel olarak bir fark var.
Hassan Syed

kabın şablonlandığı bu iki parametre de adlandırılabilir mi? örnekte isimleri yoktur. Ve ayrıca - bu örnekte 'class Container' yazılmıştır - bunun yerine 'typename Container' da yazılabilir mi?
Mat

2
@Mat: evet, aranacak terim şablon şablonu parametreleri / bağımsız değişkenleridir . Örn:template<template<class U> class V> struct C {};
Georg Fritzsche

6

Bu pasaj parçası c ++ primer kitabından. Her ne kadar bunun yanlış olduğuna eminim.

Her tür parametresinden önce anahtar kelime sınıfı veya tür adı kullanılmalıdır:

// error: must precede U with either typename or class
template <typename T, U> T calc(const T&, const U&);

Bu anahtar kelimeler aynı anlama gelir ve bir şablon parametre listesinde birbirinin yerine kullanılabilir. Bir şablon parametre listesi her iki anahtar kelimeyi de kullanabilir:

// ok: no distinction between typename and class in a template parameter list
template <typename T, class U> calc (const T&, const U&);

Bir şablon türü parametresi belirlemek için sınıf yerine typename anahtar sözcüğünü kullanmak daha sezgisel görünebilir. Sonuçta, yerleşik (sınıf dışı) türleri şablon türü bağımsız değişkeni olarak kullanabiliriz. Ayrıca, typename daha açık bir şekilde, izleyen adın bir tür adı olduğunu gösterir. Ancak, şablonlar yaygın olarak kullanıldıktan sonra C ++ 'a typename eklendi; bazı programcılar sadece sınıfı kullanmaya devam ediyor

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.