2012-12-16 79 views
2

這個問題的通用模板函數如下這樣:Function overloading and template deduction priority阻止所有模板派生類型

考慮以下類:

template<typename T1, typename T2> 
class Base {}; 

class Derived0 : public Base<double, double> {}; 

template<typename T1, typename T2, typename T3> 
class Derived1 : public Base<T1, T2> {}; 

template<typename T1, typename T2, typename T3, typename T4> 
class Derived2 : public Base<T3, T4> {}; 

而以下功能:

template<typename T> f(const T& x); // version A 
template<typename T1, typename T2> f(const Base<T1, T2>& x); // version B 

我的問題f(double)會叫version A(ok),f(Base<double, double>)會叫version B(ok),但是f(Derived1<double, double, double>)將打電話給version A(請參閱開頭的其他問題的鏈接)。

使用C++ 11,如何阻止version A和力version BBase<T1, T2>任何T1T2所有派生成員是誰?

注意:如果可能,我想避免添加助手類,並希望添加成員到提供的類。

+0

東西是不防火,但在大多數情況下工作,並且很短:http://codepad.org/HkfK7TfQ –

+0

什麼是T :: Base?構造函數? (+在什麼情況下它不會工作)? – Vincent

+0

當T不通過定義一個名爲'Base'的成員來隱藏它時,'T :: Base'是'Base '的繼承注入類名。如果'T'本身是'Base ',那麼'T :: Base'命名構造函數(但SFINAE注意那麼'f'也被忽略)。 –

回答

3

這是一個可能適合你的特質。

的性狀類:

#include <type_traits> 

template <typename, typename> struct Base { }; 

template <typename T> struct isbase 
{ 
    typedef char yes; 
    typedef yes no[2]; 

    template <typename U, typename V> static yes & test(Base<U, V> const &); 
    static no & test(...); 

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

應用:

#include <iostream> 

template <typename T> 
typename std::enable_if<!isbase<T>::value>::type f(T const &) 
{ 
    std::cout << "f(T const &)\n"; 
} 

template <typename T1, typename T2> 
void f(Base<T1, T2> const &) 
{ 
    std::cout << "f(Base<T1, T2> const &)\n"; 
} 

實施例:

template<typename T1, typename T2, typename T3> 
struct Derived1 : public Base<T1, T2> {}; 

int main() 
{ 
    std::cout << isbase<double>::value << std::endl; 
    std::cout << isbase<Base<int, char>>::value << std::endl; 
    std::cout << isbase<Derived1<bool, bool, bool>>::value << std::endl; 

    f(double{}); 
    f(Base<int, char>{}); 
    f(Derived1<bool, float, long>{}); 
} 

概括:我們可以做出更一般性狀檢查,如果一個類型從模板實例得出:

template <typename T, template <typename...> class Tmpl> 
struct derives_from_template 
{ 
    typedef char yes; 
    typedef yes no[2]; 

    template <typename ...Args> static yes & test(Tmpl<Args...> const &); 
    static no & test(...); 

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

用法:derives_from_template<T, Base>::value

+0

非常好的一段代碼。現在,我正在尋找如何在沒有特殊類的情況下爲我的特定應用程序做同樣的事情。 – Vincent

0

我想你可以給你B類模板作爲成員的標記類型,並導致一般臨時實例在存在時失敗。通常情況下,SFINAE反過來工作,但使用間接方式,它應該仍然有效。

template<typename T1, typename T2> 
class Base { 
public: 
    struct isBase {}; 
}; 

template <typename T> 
struct is_base { 
    template <typename S> char (&test(typename S::isBase*))[1]; 
    template <typename S> char (&test(...))[2]; 
    enum { value = sizeof(test<T>(0)) == 1 }; 
}; 

template <typename T> 
typename std::enable_if<!is_base<T>::value>::type f(T value) { 
    ... 
}; 

該解決方案基本上有類似的功能,以KerrekSB的解決方案,但並不需要明確的拼寫出支持的類型:它使用標籤isBasd(這或許應該被拼寫更是唯一的)來檢測Base類型或派生的對象。

+0

你能舉一個例子嗎,我不確定你在描述什麼? – Vincent

+1

在移動設備上輸入代碼只需要一段時間:-) –