// scope of the template definition【模板定義域】
extern double foo(double);
template<class type>
class ScopeRules
{
public:
void invariant() { _member = foo( _val ); }
type type_dependent() { return foo( _member ); }
private:
int _val;
type _member;
}
然後第二種情況也舉例說明:
// scope of the template instantiation【模板具現域】
extern int foo(int);
ScopeRules<int> sr;
// scope of the template instantiation
sr.invariant();
那麼在invariant中的【_member = foo( _val );】,究竟會調用哪一個函數實體呢?是scope of the template declaration【模板聲明域】中的“extern double foo( double )”,還是scope of the template instantiation【模板具現域】中的“extern int foo( int )”?如果您因爲在我們例子中用int具現的ScopeRules而選擇了後者,那麼很可惜您選錯了,因爲正確答案是意料之外的double foo。。。
至於原因,讓我們來看一下書中的解釋:在template之中,對於一個非成員名字【如本例中invariant裏面foo】的決議結果,是根據這個名字的使用是否與“用來具現該模板的實際參數類型”有關與否來決定的,如果非成員名字的使用和具現模板用的實際參數沒有關聯,那麼就以“scope of the template declaration【模板聲明域】”來決定名字歸屬;然而如果它們有關聯,那麼就以“scope of the template instantiation【模板具現域】”來決定名字歸屬;回頭看我們上面的例子可以發現,invariant中的foo與我們用來具現模板的參數int沒有關聯,所以使用“scope of the template declaration”中的double版本foo函數,下面是更詳細的解釋:
// the resolution fo foo() is not dependent on the template argument【foo函數的決議結果並不依賴於模板參數】
_member = foo( _val );
_val在我們的模板聲明中,已經被定義成一個int類型,也就是說,_val是一個類型不會變的模板類成員,無論具現這個ScopeRules的實際參數是什麼類型,都不會影響到_val本身。還有,函數的決議結果只和函數的signature【原型】有關,和函數的返回值類型什麼的無關,所以,模板具現後的_member類型並不會影響到哪一個foo函數體被選中,總之就是foo的調用與具現ScopeRules的參數毫無關聯!所以調用操作必須根據“scope of the template
declaration”來決議,而在“scope of the template declaration”域中,只有一個double版本foo函數,所以自然只有一個候選者。【此外要注意的是,這種行爲不能以一個簡單的宏擴展——比如使用一個#define宏——重現之】。
下面讓我們來看看“與具現模板類型”【type-dependent】有關的用法:
sr.type_dependent();
這個函數的內容如下:
return foo(_member);
這個例子與上一個例子不同,因爲_member肯定與具現ScopeRules的參數有關:該參數將決定_member的實際類型。所以這一次foo必須在“scope of the template instantiation”域中被決議,到了這個域中就有了兩個foo版本函數,但由於_member的被具現後的類型是int,因此這次就是int版本的foo函數出線。但是,如果ScopeRules是被unsigned int或long具現出來,那麼這裏的foo選擇就會模糊不清。最後,如果ScopeRules是被某一個用戶自己的自定義類類型具現出來,而該類沒有針對int和double實現conversion運算符【轉換運算符】,那麼foo的調用操作會被標識錯誤!但不管情況如何,都是以“scope
of the template instantiation”來決定,而不是“scope of the template declaration”來決定。
這意味着編譯器必須保持兩個scope contexts【上下文範圍】:
1):“scope of the template declaration”,用來專注於一般的template class;
2):“scope of the template instantiation”,用來專注於特定的實體;
編譯器的resolution【決議】算法必須決定哪一個纔是適當的scope,然後在其中搜索適當的name。