2013-04-04 54 views
3

我對以下問題感到困惑。我想寫一些特徵結構來測試某個類是否從另一個類派生。這可以通過boost :: is_base_of <>來解決。但是,我想測試的基類有一個免費的未定義模板參數。boost :: is_same模板化基類

下面是一些代碼示例:

template<typename T> class Base {}; 

class IntDeriv : Base<int> {}; 

class Foo {}; 

template< class TestClass > 
struct is_derived_from_Base { 
    // how to create something that does the following and forces the compiler to deduce T 
    static const bool value = boost::is_base_of< Base<T> , TestClass >::value; 
}; 

int main() { 
    cout << is_derived_from_Base<Foo> << endl;   // should print 0 
    cout << is_derived_from_Base<IntDeriv> << endl; // should print 1 
} 

的問題是如何演繹TBase<T>is_base_of。 這可能嗎?我聞到一些enable_if,但我不知道如何把它放在一起。

+0

是的,那也是我的第一次猜測。但是,有一些類似的問題可以通過一些enable_if/SFINAE魔法來解決。關鍵是編譯器實際上不需要推斷T.我只是想知道某些類是否從某個任意T派生出來的Base。 – 2013-04-04 12:50:02

+0

@jrok這是可能的,請參閱我的答案。請注意,該方法可以擴展以查找基地的類型。 – Synxis 2013-04-04 13:32:03

回答

3

你想要什麼是可能的。所使用的伎倆是在C++ 03可能的,但你沒有指定我給你的C++ 11版(C++ 03使用decltype,不可用):

template<class TestClass> 
struct is_derived_from_Base 
{ 
    template<typename T> 
    static std::true_type inherited(Base<T>*); 
    static std::false_type inherited(void*); 

    static const bool value = decltype(inherited(new TestClass()))::value; 
}; 

你可以請參閱live version here

那麼,它是如何工作的?

當實例化結構並且需要value時,編譯器將獲得返回類型inherited(new TestClass())。這將調用相應的功能:如果TestClass繼承Base<T>,則TestClass*(由new返回)可鑄造爲Base<T>*,T由編譯器自動推導出來。返回類型是std::true_type。如果TestClass不繼承Base<T>,則選擇其他過載,返回類型爲std::false_type。其餘的很簡單:std::true_type::value = truestd::false_type::value = false

還有一些極端情況:

  • 編譯錯誤使用私有繼承的結果。我不知道如何解決它,因爲我不知道答案:如果A私下繼承B,A是從B派生出來還是不是? (一般來說,私有繼承被視爲實現繼承)。另請注意,在這種情況下,A* a = new B();將不能編譯。
  • 使用私有構造函數可防止前面解釋的技巧正常工作。這將導致編譯時錯誤。由於這個方法失敗了,所以你將不得不爲這些類找到另一種方法。

注意,你必須使用以下方式:is_derived_from_Base<Foo>::value,而不是你寫(is_derived_from_Base<Foo>)。

+0

太棒了。非常有意義。我在這個方向上漂移(使用一些函數重載thingy),但沒有看到這個解決方案。非常感謝。 – 2013-04-04 15:18:18