2012-11-05 41 views
1

考慮下面的代碼序列:編譯的時候類選擇與模板的基礎

#include <iostream> 

using namespace std; 

template <typename T> 
class Base 
{ 
    public: 
     T* t; 
     void b() {} 
}; 

class D1: 
     public Base<D1> 
{ 
    public: 
     int d1; 
}; 

class D2: 
     public D1 
{ 
    public: 
     int d2; 
}; 

template <typename T> 
class Selector 
{ 
    public: 

     template <typename U> 
     void a(Base<U>& base) 
     { 
      cout << __LINE__ << endl; 
      base.b(); 
     } 

     template <typename U> 
     void a(U& u) 
     { 
      cout << __LINE__ << endl; 
     } 
}; 


int main() 
{ 
    D2 derivated; 
    Selector<D2> s; 
    s.a(derivated); 
    return 0; 
} 

我要檢查一些類(D2)是否有基地(基地),繼承任何D2的父母。 我只是不能得到Selector擊中最專業的成員功能。

回答

3

你可以搭建自己的特質來檢查一個類型是否具有任何Base<T>作爲祖先。對我來說,以下工作:

template <typename T> struct Foo { }; 

struct Bar : Foo<Bar> { }; 

struct Zip : Bar { }; 

#include <type_traits> 

template <typename T> 
class derives_from_any_foo 
{ 
    typedef char yes; 
    typedef char no[2]; 

    template <typename U> 
    static yes & test(Foo<U> const &); 

    static no & test(...); 

public: 
    static bool const value = sizeof(test(std::declval<T>())) == sizeof(yes); 
}; 

#include <iostream> 

int main() 
{ 
    std::cout << "int: " << derives_from_any_foo<int>::value << "\n" 
       << "Bar: " << derives_from_any_foo<Bar>::value << "\n" 
       << "Zip: " << derives_from_any_foo<Zip>::value << "\n"; 
} 

有通常沒有必要要求這些排序類型檢查的任何對象實例;一切都是靜止的。如果您有對象,請使用decltype來獲取其類型,或者添加類型推斷幫助器函數。

+0

的問題,這是任何類型的隱式轉換爲'富'也將返回TRUE;。這就是爲什麼boost :: is_base_of'太複雜了。 – Xeo

+0

@Xeo:是的,好點。我們希望'Foo '沒有任何隱式轉換。畢竟,它在OP的控制之下。 –

+0

@Xeo:實際上,'std :: is_base_of'是一個庫函數還是一個內置的編譯器? –

1

發生這種情況是因爲U = D2U = D1(即Base<D1>)相比是更好的選擇。你將無法用相同的函數定義來實現這一點,因爲第一個選擇總是會超過第二個選項。

更新:如果你被允許改變class Selector,然後在下面的SFINAE方式調整得到它的權利:

template<bool> struct Bool; 
template <typename T, typename = Bool<true> > 
class Selector // <---- For general cases 
{ 
public: 
    template <typename U> 
    void a(U& u) // <---- choose normal funciton 
    { 
    cout << __LINE__ << endl; 
    } 
}; 
template <typename T> 
class Selector<T,Bool<IsAnyPublicBaseof<T,Base>::value> > 
{ // <---- For the cases like `class D2` 
public: 
    template <typename U> 
    void a(Base<U>& base) // <--- choose special function 
    { 
    cout << __LINE__ << endl; 
    base.b(); 
    } 
}; 

其中內部SFINAE是,

template<typename T, template<typename> class Base> 
struct IsAnyPublicBaseOf 
{ 
    typedef char (&yes)[2]; 

    template<typename X> 
    static yes Check (Base<X>*); 
    static char Check (...); 

    static const bool value = (sizeof(Check((T*)0)) == sizeof(yes)); 
}; 

這裏是一個working demo正好是你的代碼。

另請注意,您不需要有一個Selector的對象來確定。只是使Selector::a()static方法,並使用簡單:

Selector<D2>::a(derivated); 
+0

非常感謝,但是另一個答案比您的更快一點。謝謝。 –

+0

@DragomirIvanov,兩個答案都在編譯時間,所以沒有快或慢的要點:)。 – iammilind

+0

I ment ...答案快一點,不是跑步時間:) –