2009-04-03 5 views
2

テンプレートをキャストする方法が少し失われています。私はParamVector<double>*型のパラメータをとる関数fooを持っています。私はParamVector<float>*を渡したいと思います。私はParamVectorクラスのキャスト演算子をどのようにオーバーロードするのか分かりません。誰かがこれを行う方法の例を持っていますか?ありがとう。C++テンプレートキャスト

編集:いくつかのコードを追加して、申し訳ありません、私はばかだと言い、元の質問はまったくうまくいきませんでした。

template<class T> class ParamVector 
{ 
public: 
    vector <T> gnome; 
    vector <T> data_params; 
} 

template<class T> class ParamVectorConsumer 
{ 
public: 
ParamVector<T> test; 
} 

ParamVector<float> tester; 
ParamVectorConsumer<double> cons; 
cons.ParamVector = tester 

はコンパイルに失敗します。私はそれを書く方法を知りたいので、フロートバージョンのテスターをParamVector doubleにキャストすることができます。ありがとう

EDIT2:鋳造は間違った言葉でした。私は余分なコードを書いても構いません。コンパイラがこれを受け入れて、何らかの変換コードを書くことができるようにする必要があります。

+0

はい、正確にParamVectorは何ですか?あなたが呼び出そうとしている機能は何ですか? –

+0

あなたの投稿に何か不足していますか?おそらくfooはParamVector を望んでおり、ParamVector があります。ここでT2はT1にキャスト可能ですか? –

+0

マークアップが少し明確になるように修正されました。それは疑問だったが、マークダウンはOPのテキストを食べた。 – unwind

答えて

6

は私はわからないが、多分あなたは、このようないくつかの必要があります:あなたは=使用変換演算子や演算子を選択することができます

template< typename TypeT > 
struct ParamVector 
{ 
    template < typename NewTypeT > 
    operator ParamVector<NewTypeT>() 
    { 
     ParamVector<NewTypeT> result; 
     // do some converion things 
     return result; 
    } 

    template< typename NewTypeT > 
    ParamVector(const ParamVector<NewTypeT> &rhs) 
    { 
     // convert 
    } 

    template < typename NewTypeT > 
    ParamVector& operator=(const ParamVector<NewTypeT> &rhs) 
    { 
     // do some conversion thigns 
     return *this; 
    } 


}; 
ParamVector<double> d1; 
ParamVector<float> f1; 
f1 = d1; 

- 私は両方の私の例で提供してきました。

+0

ニース。私は例で追加情報を編集して追加しました。 – bayda

+0

申し訳ありませんが、これは本当にひどいアドバイスです。これは最悪のメモリ特性を有する。私は彼のfoo関数をParamVector にするOPの必要性について質問します。任意のParamVector を取得できるように、foo関数をテンプレート化します。 –

+0

暗黙の変換もあまり好きではありません。しかし、質問された質問に対する答えです。何があなたの意見でひどいですか? – bayda

2

あなたができないために失われました - 2つのタイプは全く異なります。コードのキャストの必要性に遭遇するときは、コードとデザインの両方を非常に詳しく調べる必要があります。一方または両方が間違っている可能性があります。

1

doubleとfloatが完全に異なるサイズであるため、これを直接キャストで行うことはできません。浮動小数点数は32ありながら、ダブルスは64ビットであることを行っている

ParamVector<double> 

ParamVector<float> 

からキャストすることを余儀なくポインタは、データを誤って解釈し、あなたのゴミを与えるために起こっています。あなたはgoogle "ポインタのエイリアシング"やポインタの一般的な詳細については、これがうまくいかないかを知ることができます。

を使用すると、32ビット値の配列として解釈されるべきこれを強制する場合は、フィールドを持つ64ビット値の束であるつのアレイは、この

0 => abcdabcd12341234 
1 => abcdabcd12341234 

ようにレイアウトしている第二のためにそれについて考え、それは正しく解釈されないだろう。あなたは、または

0 => abcdabcd 
1 => 12341234 
2 => abcdabcd 
3 => abcdabcd 

のようなものを取得してもしなくてもよい12341234さんが最初に来る、または起因する単語の順序が出てどのように動作するかに何かの見知らぬ人となるように、切り替えることができます。

+0

私はそれが暗黙的なキャスティングであり、C++ wouldntはそれについて不平を言うと思いましたか? C#ではなくC++であろうか? – TStamper

+0

C++はfloatとdoubleを暗黙のキャストとして受け入れますが、暗黙のキャストとしてfloat-arrayとpointer-to-double-arrayを受け入れることはできません。 floatとdoubleは値であり、float *とdouble *はメモリオブジェクトです。 sizeof(float)はsizeof(double)と異なる場合があるので、double *としてfloat *を受け入れることはできません。 –

3

C++のよくある質問はsectionです。

希望すると助かります!

1

あなたの見出しに「テンプレートキャスト」と書いてありましたので、ParamVectorはテンプレートタイプと推測します。つまり、fooもテンプレート化でき、それがあなたの問題を解決します。

template <typename T> 
void foo(ParamVector<T> const& data) 
{ 
} 
1

タイプは無関係であるため、このようなテンプレートはキャストできません。

しかし、あなたのような、変換機能を追加することができます。

(。あなたのコードは本当に完全ではなかったので、私はどちらかの完全なコードを投稿することができますうまくいけば、あなたのアイデアを得るでしょう。)

template<class T> class ParamVectorConsumer 
{ 
public: 
ParamVector<T> test; 

template<T2> ParamVectorConsumer<T2> convert() 
{ 
    ParamVectorConsumer<T2> ret; 
    ret = this->... 
} 
2

まあ、できません。それぞれ異なる実際のテンプレートパラメータは、まったく新しいクラスを作成します。このクラスは、他のクラスとの継承関係を持たず、そのテンプレートから作成された実際の引数が異なります。

関係はありません。まあ、それぞれが同じインターフェイスを提供することを除いて、のテンプレートの中にがあり、それで同じものを扱うことができます。

しかし、静的型も動的型もどちらも関係がありません。

ここに戻って説明してください。

私がするClassTypeへのポインタを宣言すると、

Foo fp*; 

FPのように、我々はポインタにはFooの静的な型、呼んでいます。クラスのバーがfooのサブクラスである、と私は新しいバーではFP指している場合:

fp = new Bar1(); 

はその後、我々は、オブジェクトがバーの動的な型を持つFPによって指さと言います。

fp = new Bar2(); 

、これまでにもにどのようなFPポイントを知らなくても、私はFooの中で宣言した仮想メソッドを呼び出すと、コンパイラはそのことを確認することができ:BAR2も公にはFooから派生した場合

することは、私はこれを行うことができます動的な型で定義されているメソッドは、呼び出されたものです。 template< typename T > struct Baz { void doSomething(); };

Baz<int>Baz<float>について

はない関係を有する2つの全く異なるクラスタイプです。

私はBaz<int> bi*がある場合、静的型は関係がないので、私はBaz<float>にそれを指すことができません両方でdoSomething()を呼び出すことができるということです。キャストしても。コンパイラは、Baz doSotheingメソッドへの呼び出しをBaz :: doSomething()メソッドの呼び出しに「変換」する方法がありません。 には「Bazメソッド」がなく、Bazがなく、ony Baz<int>sおよびBaz<float>sおよびBaz<whatevers>がありますが、共通の親はありません。 Bazはクラスではなく、Bazはテンプレートであり、実際の型(または定数)にバインドされたTパラメータがある場合にのみ、クラスを作成する方法に関する一連の指示です。

ここでは、私たちはそれらを扱う方法が1つあります:テンプレートでは、同じインタフェースを提示し、コンパイラは実際にどのBazを扱っているか知っていれば、を静的にすることができます。そのメソッド(またはメンバ変数の静的アクセス)を呼び出します。

しかし、テンプレートはコードではなく、テンプレートはメタコードであり、クラスを合成する方法です。テンプレート内の「呼び出し」は呼び出しではありません。呼び出しを行うためにコードを記述する方法の指示です。

So.それは長く巻き込まれ、混乱していた。テンプレート定義の外には、ParamVectorとaParamVectorの間には関係がありません。だからあなたの任務はうまくいかない。

ほぼ。

実際には、テンプレートの一部のアプリケーションで、あなたはParamVector<U>Paramvector<T>を変換する方法の「レシピ」を与えるテンプレート関数を書くことができます。 TとUに注目してください。他の種類のParamVectorへの実際のテンプレートパラメータに関係なく、あらゆる種類のParamVectorを切り替えるコードを書くことができれば、それを部分的に適用されたテンプレートとしてパッケージ化することができます。 、例えば、ParamVector。

おそらくParamVector<U>を作成し、の各TをParamVector<U>に入れるために変換します。まだParamConsumer<T>にあなたを代理させることはできません。

おそらく、テンプレートと継承の両方が必要な場合があります。その場合、型に関係なくすべてのParamVectorが非テンプレートクラスから継承することも同じことができます。そして、ParamVectorsの間には関係があり、それらはすべてその基本クラスの兄弟クラスになります。

2

暗黙のキャストを実行すると、コンパイラが助けなしに行うことができることに注意してください。つまり、オブジェクトを参照(キャスト目的のみのために、オブジェクトの性質は当然変化しません)と見なし、それをその祖先の1つとして見ることができます。 2つのテンプレートインスタンスがある場合、それらのインスタンスはいずれも他のインスタンスの祖先ではありません(必ずしも同じ階層にはありません)。 コンパイラは、キャスト演算子、コンストラクタなどを探します。この段階では、アトリビューションを実行しているときや、アロケーション演算子がある場合を除いて、おそらく一時オブジェクトを作成する必要があります。テンプレートのインスタンスを使用し、他が必要とされるたびにこれが一時的なオブジェクトを作成します

template<class T> class ParamVector 
{ 
public: 
    vector <T> gnome; 
    vector <T> data_params; 

    ParamVector() 
    { 
    } 
    template <class T2> ParamVector(const ParamVector<T2> &source) 
    { 
     gnome.reserve(source.gnome.size()); 
     copy(source.gnome.begin(), source.gnome.end(), gnome.begin()); 
     data_params.reserve(source.data_params.size()); 
     copy(source.data_params.begin(), source.data_params.end(), data_params.begin()); 
    } 
}; 

:あなたの問題へ

一つの解決策は、変換コンストラクタを使用することです。大きなコンテナを扱っているなら、良い解決策ではありません。オーバーヘッドは受け入れられません。また、オブジェクトではなく参照を必要とする関数にテンプレートインスタンスを渡す場合、コンパイラは自動的に変換コンストラクタを呼び出しません(明示的な呼び出しが必要です)。