2016-10-05 4 views
1

私は(とにかく私のレベルのために)むしろ複雑なテンプレートの問題でいくつかの援助をいただければ幸いです。C++テンプレートのトラブル

最初に「システム」を説明しましょう。

バッファプレーヤーからのデータを処理し、そこから:基本的なオーディオミキシングおよびストリーミングシステムのモデリング

、それは3つの構成要素を有しています。 これらはデータで直接接続されているため、データは同じタイプのものにする必要があります。従ってBuffer<T> ~ Player<T>、ここでテンプレートと一致しなければならない。

これらは、最終的にすべての着信バッファを1人のプレーヤーに管理するのマネージャーでラップされます。

バッファとプレーヤーはどちらも異なる実装が必要なので、汎用ののインタフェースで表され、iPlayerとiBufferとなります。

simple_manager<simple_player<float>>; 

やIM最初のものでも解決策を持っているかわからない、私の試み以来、この少なくとも

simple_manager<simple_player , float>; 

を失敗:

私の目標は、このようなマネージャーを宣言することができることですこのようにして:

template <typename K> 
class iManager { 
    private: 
     K player; 
}; 

template <template <typename> class C , typename T> 
class simple_manager : iManager< C<T> > { 
    public: 
     void play(iBuffer<T> & _buffer,const audio_descriptor ad, bool * condition){ 
      player.play(_buffer,ad,condition); 
     } 


}; 

ご覧のとおり、具体的なクラスでは、Tはデータの種類をCは私が使用したい具体的なクラスのプレイヤーです。 インターフェイスには、具象プレーヤークラスを再度マークするテンプレートが1つしかありません。

simple_manager.cpp: In member function ‘void simple_manager<C, T>::play(iBuffer<T>&, audio_descriptor, bool*)’: 
simple_manager.cpp:18:12: error: ‘player’ was not declared in this scope 
      player.play(_buffer,ad,condition); 
      ^~~~~~ 

を、私はこのことを原因かわからない:だからK ~ C<T>

これは(のみ)、次のエラーでコンパイルされません。コンパイラは、iPlayerがplay()メソッドを実装しなければならないので、TがiPlayerから継承されなければならないと推論することはできません。

私はそれが実際に私はこのようなsimple_managerを定義する場合は仕事を得ることができます:

class simple_manager : iManager< simple_player<float> > {...} 

それはまだに動作しません。

class simple_manager : iManager< simple_player<T> > {...} 

私は困惑しています。もし私が<T extends iPlayer>をJavaから持っていれば、これはうまくいくかもしれませんが、コンパイル時のテンプレートは私が推測するより厳しいナットです。

ご協力いただければ幸いです!

+0

だけで名前の検索よりも多くの問題があるとして、私は、再度開くために投票し、私は考えますOPは彼の最初の例の解決策も望んでいます。あなたが同意しない場合は、もう一度閉じるために投票してください。 – TartanLlama

答えて

2

最初の問題はplayerprotectedの代わりにprivateとマークされているため、派生クラスからアクセスできないということです。あなたはそれprotected作るか、またはそれにアクセスするために、いくつかのprotectedメンバ関数を追加することができます。

template <typename K> 
class iManager { 
protected: 
    K player; 
}; 

iManager<C<T>>依存基底クラスであるので、そのメンバーは、非修飾名の検索から隠されているので、これはまだ、しかし、動作しません。これを回避するには、thisポインタを介してアクセスすることができます

void play(iBuffer<T> & _buffer,const audio_descriptor ad, bool * condition){ 
    this->player.play(_buffer,ad,condition); 
} 

はあなたの最初の例では素敵な使用方法を取得するには、指定された型からテンプレート引数を抽出するために形質を書くことができます:

template <typename T> struct extract_inner; 

template <template <typename> class C, typename T> 
struct extract_inner<C<T>> { using type = T; }; 

template <typename T> 
using extract_inner_t = typename extract_inner<T>::type; 

次にiBufferに正しい引数を供給するために使用することができる。

template <typename T> 
class simple_manager : iManager<T> { 
public: 
    void play(iBuffer<extract_inner_t<T>> & _buffer, 
       const audio_descriptor ad, bool * condition){ 
     this->player.play(_buffer,ad,condition); 
    } 
}; 

Live demo

+0

秒でさらに速く、より良い!一口... –

+0

速い答えをありがとう。私は一時的なテンプレートのパラドックスに絡み合っていました。 また、よりエレガントな方法のためのあなたのソリューションのようなものは考えられませんでした、私にとっては魔法のようです。それとも、私はまだ多くのことを学ぶ必要があります。 –

1

問題は非常に簡単です。

ほとんどすべての構文がわかりますが、1つのことが間違っています:thisキーワード。 テンプレートパラメータに応じてクラスを拡張すると、thisは種類の一種になります。基本クラスはあなたの子のテンプレートパラメータに依存するテンプレートなので、コンパイラはどの名前がベースから来ているかを知る必要があります。コンパイラがあいまいさを取り除くよう要求しない場合は、基本クラスを特化し、名前を束ね、子クラスがそれらを使用できるようにすることができます。

単に基本クラスから来る名前の前にthis->キーワードを追加し、あいまいさを削除するには:

template <template <typename> class C , typename T> 
struct simple_manager : iManager< C<T> > { 
    void play(iBuffer<T> & _buffer,const audio_descriptor ad, bool * condition){ 
      this->player.play(_buffer,ad,condition); 
    } 
};