2016-07-06 3 views
3

私は、多くの継承者(derived_i)といくつかの他の型(other)を持つクラス(base)を持っています。いくつかのクラスハンドラ(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

これはあなたの問題を解決することはできませんが、ここでは、typo: 'base_specific_method()'と 'base_speciffic_method()'です。 – songyuanyao

+0

[派生クラスを基本クラスに特化したテンプレート関数に渡す]の可能な複製(http://stackoverflow.com/questions/27988024/passing-a-derived-class-to-a-template-function-specialized-withベースクラス) – PcAF

+0

@songyuanyaoうん、ありがとう! – shved

答えて

1

baseがそうでT1base<int>、またはbase<double>のクラスを派生する可能性があること、およびその、テンプレートクラスであることを

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; 
}; 

注意。すべての可能性を数えることはできないので、テンプレートパラメータ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を使用しました。テンプレート引数リストまたはパラメータリストでも使用できるはずですが、この1つ私は最初に働いていたものでした。
技術的な詳細として、この実装は、baseから派生したクラスを持っているかどうかには依存しませんが、メソッドbase_specific_method()が存在する場合でも、あなたの問題に役立つことを願っています。あなたがbase<T>かから派生したクラスを区別するためにstd::is_base_ofstd::enable_ifを使用することができます

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

+0

新しい日 - 新しいニュース - 新しい技術! C++世界の新しい部分をありがとうございました。 – shved

関連する問題