模板中的名稱,模板名稱
一、名稱的分類
(1)受限名稱:名稱前面出現 ::, ->, .的名稱,比如::X, S::x, this->x, ::N::A<int>::s
(2)非受限名稱:除 受限名稱 外
(3)依賴型名稱:一個以某種方法依賴於模板參數的名稱。
①顯示包含模板參數的 受限名稱 和 非受限名稱 都是依賴型名稱,
比如::N::A<T>::s //受限, S<int> //非受限
②對於一個成員訪問運算符(., ->)限定的受限名稱,如果符號左邊的表達式類型依賴於模板參數,該受限名稱也是依賴型
比如 void fun(C<T>* p){ p->x; } //因為p是一個依賴型的名稱,即 x 也是一個依賴型的名稱
③對於this->b; 同②。如果是在模板出現這句話那麼b也是依賴型名稱。
template<typename T>
class C{
int b;
void fun(){
this->b = 1; //b為依賴型名稱
//但如果是 b=1; 則該表達式中b不是受限名稱,也不是依賴型名稱
}
};
④對於形如ident(x,y,z)的調用,如果其中有某個參數或者是表達式所屬的類型是一個依賴於模板參數的類型,那麼ident
也是一個依賴型名稱。
(4)非依賴型名稱:除 依賴型名稱 外
那麼現在就有四種組合
受限
非受限
依賴型
受限依賴型
非受限依賴型
非依賴型
受限非依賴型
非受限非依賴型
二、名稱查找
(1)普通查找:受限名稱 查找是在一個受限的作用域內進行的。如果該作用域是一個類,那麼查找范圍可以到達他的基類,
但不會考慮外圍作用域。比如D::a只會在類D及其基類中查找
非受限名稱 查找是由內到外的在所有外圍類中組曾地進行查找,如果是在類內部定義的成員函數的定義中,他會先查找類內部和該基類內部作用域,再查找外圍類的作用域。
(2)ADL查找:
首先查找對象應該是 非受限名稱 。這個前提很重要。
根據函數參數的類型查找關聯類 和 關聯名字空間。然後在這個查找集合中選出最佳的函數聲明。
template<typename T>
intline T max(T const& a, T const& b)
{
return a > b ? a : b; //這裡需要使用到特殊的operator > 實現,但是max不知道BigMath名字空間的存在
}
namespace BigMath{
class BigNum{};
bool operatoe > (BigNum const&, BigNum const&);
}
using BigMath::BigNum;
void g(BigNum const& a, BigNum const& b)
{
BigNum c = max(a, b);
}
所以上面的查找需要ADL查找,才能夠根據參數a, b的類型找到operator > ()的具體實現。
三、友元問題
C++ 規定: 友元的聲明在外圍類作用域中是不可見的
C++還規定:如果友元函數所在的類屬於ADL的關聯類集合,那麼我們在這個外圍類是可以找到該友元聲明的
關於 友元問題請看http://www.cnblogs.com/claruarius/p/4062112.html
四、插入式類模板名稱
首先,插入式類名稱應該是該類作用域的非受限名稱(如果是該類作用域的受限名稱,則會變成該類的構造函數,稱該名稱將訪問不到)。
模板的插入式類名稱,與普通的插入式類名稱有些區別:
類模板名稱後面可以緊跟模板實參,如果沒有緊跟模板實參那麼他們就是用模板參數來代表實參的類
template< template<typename> class TT> class X {};
template<typename T> class C{
C* a;
C<void> b;
X<C> c; //沒有跟模板實參,C將不會被看做是模板
X<::C> d; //<::之間沒有空格,<:是[ 的另一種表示
X< ::C> e; //正確
}
五、解析模板
大多數程序設計語言編譯都包含兩個我最基本的步驟:
符號標記(詞法掃描)和解析。
(一)依賴型
類型名稱
下面是一個很經典的例子,
①先是定義一個類模板A,然後在另一個類模板B中引用該模板A中的一個名稱x,
②然後顯示特化類模板A變成類型C,其中改變了名稱x的含義
③調用實例化後的類模板B的一個成員函數。
template<typename T>
class Trap [
public:
enum{ x }; //(1)這裡的x不是一個類型
];
template<typename T>
class Victim{
public:
int y;
void poof(){
Trap<T>::x*y; //這裡x*y究竟是乘積還是聲明一個指針y?
}
};
template<>
class Trap<void>{
public:
typedef int x; //這裡改變了x的含義
};
void boom(Victim<void>& boom)
{
boom.poof();
}
解決辦法:
C++規定:通常而言,
依賴型受限名稱並不會代表一個類型,除非在該名稱的前面加上關鍵字
typename
當類型出現以下前3個性質時,就應該在該名稱前面添加typename。
(1)名稱出現在類模板中
(2)名稱是受限名稱
(3)名稱不是用於指定基類繼承列表中,也不是位於引入構造函數的成員初始化列表中。
(4)名稱依賴於模板參數
(二)依賴型
模板名稱
如果模板名稱是依賴型名稱,那麼位於限定符後面的模板名稱與<後面的模板實參應該如何解析,就需要在
受限的依賴型模板名稱前面加上關鍵字
template
(三)using 與 private 繼承
(1)受限的類名
template<typename T>
class BXT{
public:
typedef T Mystery;
template<typenaeme U>
struct Magic;
};
template<typename T>
class DXT : private BXT<T>{
public:
using typename BXT<T>::Mystery;
Mystery* p;
};
(2)受限的模板名(這個是錯誤的,書上是這麼說的,但是我在VS2013是可以的)
template<typename T>
class DXTM : private BXT<T>{
public:
using BXT<T>::template Magic;
Magic<T>* plink;
};
(四)派生類與類模板
(1)非依賴型基類
對於模板中的非依賴型基類, 如果在它的派生類中查找一個非受限名稱,那就會先查找這個非依賴型基類然後查找模板參數列表。
(2)依賴型基類
C++規定:非依賴型名稱將會在看到第一時間進行查找
C++聲明:非依賴型名稱不會在依賴型基類中進行查找
(這個給我們創造了延遲查找的機會,即將名稱變為依賴型,因為依賴型名稱也要在實例化時才進行查找)
template<typename X>
class Base{
public:
int basefield; //非受限名稱
typename int T;
};
template <typename T>
class DD :public Base<T>{
public:
void f(){ basefield = 0; }; //①非依賴型的名稱一開始就查找到了,並綁定了int
};
template<>
class Base<bool>{
public:
enum{ basefield = 42 }; //②特化的時候改變了原來的含義
};
int _tmain(int argc, _TCHAR* argv[])
{
DD<bool> d;
d.f();
return 0;
}
所以可以借助依賴型延遲查找的特性,將basefield變成依賴型,即將①變成: this->basefield = 0;
利用依賴型查找的延遲特性,也可以啟用類模板的多態
template<typename T>
class B{
public:
enum E{ e1, e2, e3};
virtual void zero(E e = e1);
virtual void one(E&);
};
template<typename T>
class D : public B<T>{
public:
void f(){
typename D<T>::E e;
this->zero(); // D<T>::zero()會禁止虛函數調用
this->one(e); //one()的參數就是依賴型,不過最好還是使用this指針
}
};
但是上面的一切都在VS2013都解決了,比如可以不讓basefield 成為依賴型仍然可以正確的實例化。
可能編譯器廠商已經支持了,不過標准還是遵守吧。
淘寶網中的運費模板名稱寫什
隨意寫的 建議你分個類 重量類似起個名字為一個運費模板
網店裡物流設置裡模板名稱是什
這個隨便你設置名稱的,就是個代號而已。只是好讓你自己區分。