2014-08-27 65 views
3

標題引自此SO answer。它正在討論使用SFINAE來檢測具有給定簽名的成員函數的存在,並在處理繼承的成員函數時指出接受的答案中的方法失敗。特別是,給出的解釋如下模板實例化不會「繼承」

如果你不是已經明白這個問題,那麼看看頭文件中std::shared_ptr<T>的定義就會顯示出來。在那個實現中,std::shared_ptr<T>是從它繼承的基類派生的operator*() const。因此,構成「找到」U = std::shared_ptr<T>的運算符的模板實例化SFINAE<U, &U::operator*>將不會發生,因爲std::shared_ptr<T>本身沒有operator*(),並且模板實例化不會「繼承」。

使用「sizeof()技巧」,僅僅檢測T是否具有某些成員函數mf(請參閱此答案和註釋),這一障礙不會影響衆所周知的SFINAE方法。

使用從答案的術語,是用什麼作爲T::mf模板參數來實例化一個類型VS編譯器來確定它通過一個函數模板參數推導的區別? 「模板實例化不會繼承」是什麼意思?最後,爲什麼不影響檢查是否存在成員,如here

回答

3

最小化例如:

struct A { 
    void a() const; 
}; 

struct B : A {}; 

template<typename U, void (U::*)() const> struct SFINAE {}; 
template<typename U> void Test(SFINAE<U, &U::a>*) { } 

int main(void) 
{ 
    Test<B>(0); // doesn't compile 
    return 0; 
} 

Demo

的問題是,當B::aA繼承的&B::a的類型實際上是「指針的A構件」 - 和,而通常的指針到成員的鹼基可以被隱式轉換爲指針 - 根據§14.3.2[temp.arg.nontype]/p5,此轉換不適用於非類型模板參數:

對每個表達式執行以下轉換用作 非類型模板參數。如果非類型的模板參數不能被轉換爲對應的模板參數 的類型,那麼該程序是格式不正確的。類型的指針

  • [...]
  • 對於非型模板參數成員函數, 如果模板參數爲std::nullptr_t型時, 空構件指針轉換(4.11 ) 被申請;被應用;否則,不適用 轉換。如果模板參數表示一組 重載成員函數,則匹配成員函數將從集合(13.4)中選擇 。