2017-03-20 14 views
1

作成されたオブジェクトが特定のタイプである場合にのみ、メンバ関数定義でクラステンプレートを作成できますか?オブジェクトがX型である場合、クラステンプレート、メンバ関数定義?

私はint型またはdouble型を格納するために使用するテンプレートクラスを作成しましたが、倍精度用にも精度を設定できます(myclassで作成されたオブジェクト< double>にはこの機能が必要ですが、myclass < int>それが全く存在する必要はありません)。

私は基本クラステンプレートを使用し、それを使用して新しいクラス "myInt"、 "myDouble"を作成し、myDoubleクラスでのみ機能を実装することができますが、機能を定義するためには、関数とメンバ変数)がクラステンプレートの倍精度化のために使用できますか?

のは、私が何をしたいのかを示すために例を追加してみましょう:

#include <iostream> 
#include <iomanip> 

class commonBase{ 

public: 
    void setState(int state); 
    virtual void print() = 0; 
private: 
    int _my_state; 
}; 


template <typename T> 
class generalObject : public commonBase { 
public: 
    void value(T value); 
    void print(){ std::cout << "My value: " << _my_value << std::endl; } 
private: 
    T _my_value; 
}; 


template <typename T> 
void generalObject<T>::value(T value){ 
    _my_value = value; 
} 

// Is there any way do specialize only only whats different from the generalObject template? 
// Here I thought I could specialize the case where a generalObject is created of <double>, but 
// when I do, nothing is derived from generalObject (or at least not visible as far as I can tell) 
template<> 
class generalObject<double>{ 
public: 
    void setPrecision(int precision){ _my_precision = precision; } 

    // here I would like a special implementation of print(), which overrides the print() in generalObject 
    // and instead also prints according to the precision set when the object is of <double> type. 
    // Row below an example which doesn't work (compiler error, _my_value undefined) 
    void print(){ std::cout << "My value: " << std::setprecision(_my_precision) << _my_value << std::endl; } 

private: 
    int _my_precision; 
}; 


int main(int argc, char* argv[]){ 

    generalObject<int> o1; 
    o1.value(1); 
    o1.print(); 
    o1.setState(1); //inherited from the commonBase 

    generalObject<double> o2; 
    o2.setPrecision(2); 
    o2.value(2); //here value isn't available (compile error) 
    o2.print(); 
    o2.setState(123); //also isn't available (compile error) 


} 
+1

おそらくテンプレートの特殊化が必要です –

+0

関数の部分は簡単で、クラステンプレートの特殊化は必要ありません。問題は、データメンバーの存在/非存在を望み、それが何らかの専門化に効果的につながることです。 – lapk

答えて

0

確かに。

template <typename T> class Poly; 
void set_precision(Poly<double>* self, int a) {}; 

あなたは本当にあなたがして追加することができ、ドット表記する場合:私はあなたが達成しようとしているものを考えるべきだと思うしかし

template <typename T> class Poly { 
    public: void set_precision(int a){::set_precision(this,a);} 
    ... 

を。 MyIntとMyDoubleが異なるフィールドと異なるメソッドと異なる実装を持つ場合、おそらく異なるクラスである必要があります。

0

これはtemplate specializationを使用して解決できます。

我々は最初の...

template< typename T > 
struct myclass 
{ 
    // common stuff 
}; 

を、共通のテンプレートを定義...とdoubleのためにそれを専門:

template<> 
struct myclass<double> 
{ 
    int precision = 10; 
    void setprecision(int p){ precision = p; } 
}; 

setprecision()方法のみmyclass<double>のために呼び出すことができます。コンパイラは、myclass<int>のように他のもののために呼び出そうとすると文句を言うでしょう。

int main() 
{  
    myclass<double> d; 
    d.setprecision(42); // compiles 

    myclass<int> i; 
    i.setprecision(42); // fails to compile, as expected 
} 

Demo.

0

質問はここで、その後、メンバ関数についてのであれば、クラステンプレートの特殊化せずにそれを行うための方法の一つである:

#include <iostream> 
#include <type_traits> 

template <typename T> 
struct Type { 
    template <typename U = T, 
      typename = typename std::enable_if<std::is_same<U, double>::value>::type> 
    void only_for_double() { 
    std::cout << "a doubling" << std::endl; 
    } 
}; 

int main() { 
    Type<int> n; 
    Type<double> d; 

// n.only_for_double(); // does not compile. 
    d.only_for_double(); 
} 

Example on ideone.com

あなたの場合テンプレートパラメータに基づいてデータメンバーのプレゼンスが必要な場合は、何らかの専門化を行う必要があります。その場合はプロより簡単に、対応する専門化に関数を入れるのが簡単です。

編集:OPの後でより具体的に質問 これは、余分なクラスと仮想機能を取り除くことなくそれを行うための1つの方法です。それが役に立てば幸い。

#include <iostream> 
#include <iomanip> 

template <typename T, typename Derived = void> 
class commonBase { 
    public: 
    void setState(int state) { 
     _my_state = state; 
    } 
    void value(T value) { 
     _my_value = value; 
    } 

    template <typename U = Derived, 
       typename std::enable_if<std::is_same<U, void>::value, 
             void * >::type = nullptr> 
    void print() const { 
     std::cout << "My value: " << _my_value << std::endl; 
    } 

    template <typename U = Derived, 
      typename std::enable_if<!std::is_same<U, void>::value, 
             void * >::type = nullptr> 
    void print() const { 
     static_cast<Derived const *>(this)->_print(); 
    } 
    protected: 
    T _my_value; 
    int _my_state; 
}; 

template <typename T> 
class generalObject : public commonBase<T> { 
}; 

template<> 
class generalObject<double> : public commonBase<double, generalObject<double>> { 
    private: 
    friend commonBase<double, generalObject<double>>; 

    void _print() const { 
     std::cout << "My value: " << std::setprecision(_my_precision) << 
        _my_value << std::endl; 
    } 

    public: 
    void setPrecision(int precision){ _my_precision = precision; } 

private: 
    int _my_precision; 
}; 


int main(){ 
    generalObject<int> o1; 
    o1.value(1); 
    o1.print(); 
    o1.setState(1); 

    generalObject<double> o2; 
    o2.setPrecision(2); 
    o2.value(1.234); 
    o2.print(); 
    o2.setState(123); 
} 

Same code on ideone.com

0

クラステンプレートのメンバ関数を持っている基本的な方法いくつかのテンプレートパラメータのためだけに存在し、それらのテンプレートパラメータのためのクラステンプレートの特殊化を作成することです。

template<typename T>class X{ 
    // general definition 
}; 

template<>class X<double>{ 
    // double-specific definition 
}; 

これの欠点は、専門分野が一般的なものを複製する必要があることです。あなたはそれを他の方法で行うことができ、また

template<typename T>class Xcommon{ 
    // common stuff 
}; 
template<typename T>class X: public Xcommon<T>{ 
    // general definition 
}; 

template<>class X<double>: public Xcommon<double>{ 
    // double-specific definition 
}; 

:派生クラスで共通のものを入れて、ベースでエキストラこれに対処する1つの方法は、基本クラステンプレートに共通物事を動かすことです、ベースを特化する:

template<typename T>class Xextras{ 
    // empty by default 
}; 
template<typename T>class X: public Xextras<T>{ 
    // common definition 
}; 

template<>class Xextras<double>{ 
    // double-specific definition 
}; 

いずれかの方法で動作します。それは詳細によります。

これらのメソッドは、どちらもデータメンバーとメンバー関数で機能します。

また、enable_ifを使用すると、テンプレートパラメータが必須条件を満たしていない場合に、過負荷解決によってメンバー関数が選択されないことを意味できます。これには、メンバ関数自体がテンプレートである必要があります。

template<typename T>class X{ 
    template<typename U=T> // make it a template, 
    std::enable_if<std::is_same_v<U,double>> double_specific_function(){ 
     // do stuff 
    } 
}; 

他の選択肢がない場合を除き、私は、このオプションをお勧めしません。

関連する問題