2012-07-12 39 views
3

假設我有這樣的功能:添加模板函數的特化後

template<typename T> inline 
typename std::enable_if<has_member_foo<T>::value,int>::type 
foo(T const &t) { 
    return t.foo(); 
} 

template<typename T> inline 
typename std::enable_if<!has_member_foo<T>::value,int>::type 
foo(T const&) { 
    return 0; 
} 

template<typename T> inline 
int call_foo(T const &t) { 
    return sizeof(T) + foo(t); 
} 

這主要工作正常,但如果我以後添加的過載特定類型:

inline int foo(std::string const &s) { 
    return s.size(); 
} 

,我添加它call_foo()定義後, 過載不使用call_foo()。 但是,如果我在call_foo()的定義之前移動了重載代碼,則會使用它。

爲什麼在第一種情況下使用不超載​​? 當call_foo()被實例化在代碼中其他地方使用的地方時, 編譯器已經看到了的重載,所以爲什麼不使用它?

請注意,我的原始代碼具有foo()函數作爲類似模板的foo_traits類的靜態成員函數類似地使用enable_if保護。 代碼工作,即,使用模板類特例,即使call_foo()後提供,所以爲什麼不獨立的重載函數?

如果它的事項,我在Mac OS X 10.7.4使用g++ 4.6。

+1

吹毛求疵:你'FOO(的std :: string常量&)'是過載,而不是專業化(它不是一個模板函數)。 – xtofl 2012-07-12 14:17:49

+0

@xtofl:fixed;謝謝。 – 2012-07-12 14:30:03

回答

3

如果你把你的標準(C++ 98反正)到14.6.4.2/1您閱讀:

函數調用依賴於一個模板參數,如果 函數名是不合格-id但不是模板ID,該 候選功能使用通常的查找規則(3.4.1,3.4.2 ),除了發現:

- 對於使用不合格的名稱查找查找的一部分(3.4 .1), 只有函數聲明與模板外部鏈接 def找到上下文。

在這種情況下,template-id表示<template-params>合格的模板名稱。這非常清楚地說明了您在程序中觀察到的內容,即只考慮在模板定義的上下文中可見的函數。當你想想看,如果這是不是其次它,從而違反了一個定義規則,這將是可笑容易基於更改模板的含義的情況下。