2016-07-06 45 views
3

我有一個類(base),它有許多繼承者(derived_i)和一些其他類型(other)。我想在某些類處理程序中使用模板方法(caller),它以不同方式處理base的繼承方,然後從其他類型處理。使模板函數去源代碼繼承者和其他

這是我講的一個示例代碼。

#include <iostream> 

using namespace std; 

template <typename T> 
class base { 
public: 
    base (T val = T()) 
     : m_val(val) 
    {} 
    base (const base &other) 
     : base(other.m_val) 
    {} 
    virtual void base_specific_method() 
    { 
     cout << __func__ << " method called: " << m_val << endl; 
    } 
    void each_class_has_this() { 
     cout << __func__ << " this is boring..." << endl; 
    } 
    T m_val; 
}; 
class other { 
public: 
    void each_class_has_this() { 
     cout << __func__ <<" this is boring..." << endl; 
    } 
}; 
class derived_i : public base <int> 
{ 
public: 
    derived_i() : base <int> (10) 
    {} 
    virtual void base_specific_method() 
    { 
     cout << __func__ <<" Hey! I'm interesting derived! And 10 == " << m_val << endl; 
    } 
}; 

template <typename T> 
class caller { 
public: 
    caller (T val = T()) 
     : m_val(val) 
    {} 
    void call() { 
     p_call(m_val); 
    } 
private: 
    template <typename T1> void p_call (T1 &val) 
    { 
     val.each_class_has_this(); 
    } 
    template <typename T1> void p_call (base<T1> &val) 
    { 
     val.base_specific_method(); 
    } 
private: 
    T m_val; 
}; 

int main() 
{ 
    caller<other> c1; 
    caller<base<double> > c2; 
    caller<derived_i > c3; 

    c1.call(); 
    c2.call(); 
    c3.call(); 
} 

它編譯g++ -std=c++11 test.cpp和輸出是下一個:

each_class_has_this this is boring... 
    base_specific_method method called: 0 
    each_class_has_this this is boring... 

雖然我很期待

each_class_has_this this is boring... 
    base_specific_method method called: 0 
    base_specific_method Hey! I'm interesting derived! And 10 == 10 

有什麼辦法來改變這種代碼,以使其適合我的要求?

這個問題似乎是another question的重複,但正確的答案導致了這個問題,我在這裏面對。

P.S.沒有辦法使baseother成爲一個類的繼承者。 =(

+0

它不會解決你的問題,但這裏有一個錯字:'base_specific_method()'和'base_speciffic_method()'。 – songyuanyao

+0

[將派生類傳遞給專用於基類的模板函數](http://stackoverflow.com/questions/27988024/passing-a-derived-class-to-a-template-function-specialized-with -base-class) – PcAF

+0

@songyuanyao是的,謝謝! – shved

回答

1

您可以使用std::enable_ifstd::is_base_of區分base<T>或不派生的類。

template <typename T, typename TT = void> 
class caller { 
public: 
    caller (T val = T()) 
     : m_val(val) 
    {} 
    void call() { 
     p_call(m_val); 
    } 
private: 
    template <typename T1> typename std::enable_if<!std::is_base_of<base<TT>, T1>::value>::type p_call (T1 &val) 
    { 
     val.each_class_has_this(); 
    } 
    template <typename T1> typename std::enable_if<std::is_base_of<base<TT>, T1>::value>::type p_call(T1& val) 
    { 
     val.base_specific_method(); 
    } 

private: 
    T m_val; 
}; 

注意base是一個模板類,這意味着T1可能會派生類的base<int>,或base<double>,等等。我們無法計算所有可能性,因此需要將模板參數TT指定爲提示。然後用它作爲:

caller<other> c1; 
caller<base<double>, double> c2; 
caller<derived_i, int> c3; // derived_i derived from base<int> 

c1.call(); 
c2.call(); 
c3.call(); 

結果:

each_class_has_this this is boring... 
base_specific_method method called: 0 
base_specific_method Hey! I'm interesting derived! And 10 == 10 

LIVE

或者你可以做一個最基礎類,使之簡單:

class abstract_base { 
public: 
    virtual void base_specific_method() = 0; 
    virtual ~abstract_base() {} 
}; 
template <typename T> 
class base : public abstract_base { 
    ... 
}; 
... 
template <typename T> 
class caller { 
    ... 
    template <typename T1> typename std::enable_if<!std::is_base_of<abstract_base, T1>::value>::type p_call (T1 &val) 
    { 
     val.each_class_has_this(); 
    } 
    template <typename T1> typename std::enable_if<std::is_base_of<abstract_base, T1>::value>::type p_call(T1& val) 
    { 
     val.base_specific_method(); 
    } 
    ... 
}; 

LIVE2

2

可以使用SFINAE獲得所需的行爲:

添加類has_specific這樣的:

template <typename T> 
class has_specific 
{ 
    typedef char one; 
    typedef long two; 

    template <typename C> static one test(typeof(&C::base_specific_method)) ; 
    template <typename C> static two test(...);  

public: 
    enum { value = sizeof(test<T>(0)) == sizeof(char) }; 
}; 

,改變你的p_call定義是:

template <typename T1=T> 
typename enable_if<!has_specific<T1>::value,void>::type 
p_call (T1 &val) 
{ 
    val.each_class_has_this(); 
} 

template <typename T1=T> 
typename enable_if<has_specific<T1>::value,void>::type 
p_call (T1 &val) 
{ 
    val.base_specific_method(); 
} 

在這種情況下,我在返回類型中使用了SFINAE,應該可以在模板參數列表或參數列表中使用它,但是這個是我第一個工作的人。
作爲技術細節,此實現不取決於您是否從base派生類,但如果方法base_specific_method()存在,但我希望它仍然有助於解決您的問題。

Try it online
has_specific taken from here
return type SFINAE taken from here

+0

新的一天 - 新的消息 - 新技術!感謝您使用C++世界的新部分。 – shved