2011-10-30 2 views
4

次のコードをコンパイルするにはどうすればよいですか?クラスとプリミティブ型のためにこのテンプレートクラスをコンパイルするにはどうすればよいですか?

私はそれがGetterFnのための私のtypedefをコンパイルしようとするため、コンパイラはV<double>に満足していないですが、私はGetterFnGetCalc()は、クラスのために利用可能になりたい、しかし、プリミティブ型では無視することを実現しています。

このクラスをどのように再コードする必要がありますか?

#include <vector> 

using namespace std; 

class Bar 
{ 
    public: 
     float getMyFloat() const { return 42.5; } 
}; 

template< typename T > 
class V 
{ 
    public: 
     typedef float (T::*GetterFn)() const; 
     void getCalc(std::vector<double>& vec, GetterFn fn) const 
     { 
      vec.clear(); 
      for (size_t i=0; i<m_v.size(); ++i) 
       vec.push_back(m_v[ i ].*(fn)()); 
     } 

    private: 
     vector<T> m_v; 
}; 

int main(int argc, char** argv) 
{ 
    V<Bar> vb; // ok 
    V<double> vd; // compiler not happy 
} 

答えて

1

基本的なタイプで何をしたいのかわからなくても、完全なソリューションを提案するのは少し難しいです。しかし、心臓には、std::is_fundamentalタイプの形質を使用することをお勧めします。

#include <vector> 
#include <type_traits> 
#include <cstddef> 

class Bar 
{ 
public: 
    float getMyFloat() const { return 42.5; } 
}; 

template< typename T > 
class V 
{ 
private: 

    static const bool m_primitive = std::is_fundamental<T>::value; // convenience 

    template <bool B, typename U> struct Helper; 

    template <typename U> struct Helper<false, U> 
    { 
    typedef float (T::*GetterFnType)() const; 
    void getCalc(std::vector<double> & v1, std::vector<U> const & v2, GetterFnType f) 
    { 
     v1.clear(); 
     for (std::size_t i = 0; i < v2.size(); ++i) 
     v1.push_back((v2[i].*f)()); 
    } 
    }; 

public: 

    // use Helper<m_primitive, T>::GetterFn and Helper<m_primitive, T>::getCalc() here 

private: 
    std::vector<T> m_v; 
}; 

int main(int argc, char** argv) 
{ 
    V<Bar> vb; // ok 
    V<double> vd; // compiler also happy 
} 

あなたはおそらく、実際にいくつかのstd::enable_ifを行う必要があるでしょう:あなたはメンバ関数の全体のコレクションが存在する場合

は条件付きでのみ、おそらくメンバーヘルパークラスにそれらをラップすることは、1つのアイデアです実装。あなたが詳細を投稿すると、私たちは詳しく説明することができます。あなたはより広範な再設計に開放している場合は

は、コンラートの答えは、ややクリーンでシンプルになり、最終的な結果のように感じるが、その後、再び、私はあなたが明確にでき

+0

私はあなたの答えをサンドボックスatmで試しています - 私は同意します - 私はKonradの答えがはっきりしているのが好きですが、私は渡す必要のあるメソッドポインタ(クラスのみ)を扱うtypedefが必要です。基本的には、クラス内でいくつかの作業を行うメソッドポインタを渡すことができるようにします。プリミティブはこのポインタを提供する必要はありません(全く意味をなさないので)、そのメソッドを持つべきではありません。 – kfmfe04

+0

@ kfmfe04:私はその部分を理解しています。私が知らないことは、あなたのクラスが行う実際の仕事と、それが「T」が基本的であるかどうかに依存する方法です。実際の実装を書くときには、ある種のコンパイル時の分岐が必要になります。 –

+0

クラスVは、実際には、インデックス型とデータ型を取る時系列クラスの非常に単純化されたバージョンです。データタイプは、基本的であっても非基本的であってもよい。非ファンダメンタルについては、私は呼び出し元が(プライベートデータメンバーを使用して)結果のベクトルを記入するために呼び出されるメソッドに名前を付けることを許可したいと思います。私は、発信者にデータの内部実装を心配させたくありません。 – kfmfe04

1

doubleはメンバー機能を持つことができません。 Ergoでは、非メンバ関数を使用します。

+0

:-)複雑なテンプレートブードゥー教の賛成ですべてですあなたの答えは少しですか?どの機能を動かすことを提案し、どこで? – supertopi

3

Alfのちょっとしたスニークな答えが本当に簡単な方法です。

void getCalc(std::vector<double>& vec) const 
{ 
    vec.clear(); 
    for (size_t i=0; i<m_v.size(); ++i) 
     vec.push_back(get_value(m_v[ i ])); 
} 

してからちょうど適切get_valueをオーバーロード::もちろん

double get_value(double value) { return value; } 

double get_value(Bar value) { return value.getMyFloat(); } 

を、より説明的な名前を代わりにGetterFnだけの値を取得するには、オーバーロードフリー機能を使用し、メンバ関数ポインタであるのget_valueよりお勧めします。

+0

+1私は簡潔さと明快さのためにあなたの答えが気に入っていますが、ケレックの答えはメソッドポインタtypedefを扱うためのもう少しを提供します。 – kfmfe04

関連する問題