C++模板(template)中typename
1、typename關(guān)鍵字
在聲明template參數(shù)時, 前綴關(guān)鍵字class和typename可以互換,但在使用模板參數(shù)T的內(nèi)部類型名稱即嵌套從屬名稱時只能用typename。
在C++標(biāo)準(zhǔn)化的過程中,引入關(guān)鍵字typename是為了說明:模板類型參數(shù)內(nèi)部的標(biāo)識符(associated type,常見于STL中的各種容器)也可以是一個類型:
比如:
template<typename T>
class MyClass
{
typename T::SubType* ptr;
}
這里介紹模板內(nèi)參數(shù)名稱的幾個概念;
從屬名稱(dependent names): 模板(template)內(nèi)出現(xiàn)的名稱, 依賴于某個模板(template)參數(shù), 如T t;
嵌套從屬名稱(nested dependent names):從屬名稱在class內(nèi)呈嵌套裝, 如T::const_iterator ci;
非從屬名稱(non-dependent names): 不依賴任何template參數(shù)的名稱, 如int value;
任何時候在模板(template)中指涉一個嵌套從屬類型名稱, 需要在前一個位置, 添加關(guān)鍵字typename;
如果不特定指出typename, 嵌套從屬名稱, 有可能產(chǎn)生解析(parse)歧義,可能會報錯(GCC): error: need 'typename' before 'T::xxx' because 'T' is a dependent scope。
比如:
template<typename T>
class MyClass
{
/*typename*/ T::SubType* ptr;
}
上述程序中,第二個typename被用來說明,SubType是定義與類T內(nèi)部的一種類型,也就是associated type,因而,ptr是一個指向T::SubType類型的指針。如果不使用typename,T::SubType會被優(yōu)先看做T的一個靜態(tài)成員,也就是一個具體而變量或?qū)ο螅谑牵旅娴谋磉_(dá)式:
T::SubType* ptr;
編譯器此時就無法辨別這SubType是什么,因為SubType可能是模板參數(shù)T內(nèi)的一個static變量,ptr可以看成一個全局變量,此時代碼會被看做類T的靜態(tài)成員SubType和ptr的乘積,或者SubType可能是一個typedef比如
class Class_T{
typedef int SubType;
...
};
那上面代碼轉(zhuǎn)化過來就是這樣:
int *x;
2、嵌套從屬名稱使用typename的幾個場景
a、模板內(nèi)出現(xiàn)的名稱如果依賴于某個模板參數(shù),稱之為從屬名稱(dependent name)。如果從屬名稱在class內(nèi)呈嵌套狀,我們稱為嵌套從屬名稱(nested dependent name),舉例如下:
template<typename T>
void print(const T & container)
{
T::const_iterator iter(container.begin());
cout << *iter << endl;
int value = *iter;
return;
}
在上述代碼中,iter 的類型是依賴于模板參數(shù)T的,因此被稱為 從屬名稱;
同理,value的類型是語言內(nèi)置類型,不依賴于任何模板參數(shù),因此被稱為 非從屬名稱;
C++編譯器在面對從屬名稱時,如果此時該從屬名稱又嵌套了其他類型,如此處的 iter就是T::const_iterator類型,這里的T::const_iterator 稱為嵌套從屬類型名稱(嵌套于T類型,從屬于模板參數(shù)T)
或者
template<typename T> // typename allowed (as is "class")
void f(const T& container, // typename not allowed
typename T::iterator iter); // typename required
上述的T并不是嵌套從屬類型名稱 (它并非嵌套與任何“取決于模板參數(shù)”的東西內(nèi)),所以聲明container時并不需要以typename為前導(dǎo)。
但T::iterator是個嵌套從屬類型名稱,所以必須以typename為前導(dǎo)。
b、某個模板類里面typedef類型時,如果這個類型與模板參數(shù)T相關(guān),就需要使用typename。即這樣的形式:
template <class T>
class Test
{
public:
typedef map<int, T> TEMPLATE_MAP; //TEMPLATE_MAP不需要typename,因為它不依賴其他的名稱
typedef map<int, T>::iterator TEMPLATE_MAP_ITER; //error! 嵌套從屬名稱,依賴其他類的iterator名稱
typedef typename map<int, T>::iterator TEMPLATE_MAP_ITER; //yes
};
c、例外:嵌套從屬類型名稱, 如果是基類列表(base class list)和成員初值列(member initialization list)中,不使用typename;
/*
* BInsertSort.cpp
*
* Created on: 2014.4.17
* Author: Spike
*/
#include <iostream>
#include <vector>
using namespace std;
struct Number {
Number(int x) {
std::cout << "Number = " << x << std::endl;
}
};
template<typename T>
struct Base{
typedef Number Nested;
};
template<typename T>
class Derived: public Base<T>::Nested { //不用typename
public:
explicit Derived(int x) : Base<T>::Nested(x) { //不用typename
typename Base<T>::Nested temp(7); //必須使用
}
};
int main () {
Derived<int> d(5);
return 0;
}
總結(jié)
以上是生活随笔為你收集整理的C++模板(template)中typename的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: exists sql用法_SQL关于IN
- 下一篇: python bottle框架 重定向_