2012-02-29 11 views
2

私は、さまざまなタイプのユーザー提供オブジェクトのバッファを管理するタスクランタイムシステムを実装しています。さらに、すべてのオブジェクトはバッファに格納される前にラップされます。 、テンプレートクラスのインスタンスへのポインタのベクトル

template <typename T> 
class Wrapper { 
private: 
    T mdata; 
public: 
    Wrapper() = default; 
    Wrapper(T& user_data) : mdata(user_data) {} 
    T& GetData() { return mdata; } 
    ... 
}; 

template <typename T> 
class Buffer { 
private: 
    std::deque<Wrapper<T>> items; 
public: 
    void Write(Wrapper<T> wd) { 
     items.push_back(wd); 
    } 

    Wrapper<T> Read() { 
     Wrapper<T> tmp = items.front(); 
     items.pop_front(); 
     return tmp; 
    } 
    ... 
}; 

今、ランタイムシステムは、タスクを処理するのは、それぞれのサブセットで動作:ランタイムは、ユーザーが提供するオブジェクトのタイプを知らないので、ラッパーおよびバッファクラスがテンプレート化されています前述の緩衝液。したがって、各バッファは1つ以上のタスクによって操作される。これは、タスクがバッファを共有する可能性があるため、タスクがバッファへの参照を保持しなければならないことを意味します。

私の問題がどこにあるか。これは、次のとおりです。 1バッファがtempletedバッファクラスに基づいて、異なる種類(である) 2(この数は、コンパイル時には不明です)各タスクがバッファの数への参照を維持する必要があります) )。 3)タスクは、これらの参照をアクセスバッファに使用する必要があります。

バッファクラスに基本クラスを持っているし、その後メソッドはバッファクラスからと読むを書くので、基底クラスのポインタを使用するためにはポイントがありませんがtempletedされているので、仮想することはできません。

だから私は、Taskクラスは、次のようになります場合は、無効ポインタとしての参照を維持するために考えていた:

class Task { 
private: 
    vector<void *> buffers; 
public: 
    template<typename T> 
    void AddBuffer(Buffet<T>* bptr) { 
     buffers.push_back((void *) bptr); 
    } 

    template<typename T> 
    Buffer<T>* GetBufferPtr(int index) { 
     return some_way_of_cast(buffers[index]); 
    } 
    ... 
}; 

これに伴う問題は、私はからの有効なポインタを取得する方法がわからないということですバッファにアクセスするには、voidポインタを使用します。つまり、私はバッファが指し示すオブジェクトの型を保持する方法を知らない[​​インデックス]

これを手伝ったり、他の解決方法を提案できますか?

EDIT:バッファはランタイムシステムの実装の詳細のみであり、ユーザーはその存在を認識していません。

+0

ええと、私はこれがテンプレートではうまくいかないと思います。実行時間が多すぎる多態性が必要です。私は頭の中から2つのオプションを提案したいと思います:1.サブタイプポリモーフィズムをどこにでも使い、 'Task'クラスが必要とするすべてのものを提供する一般的な抽象基本クラスから型を継承させます。 2.ブースト。しかしどちらも本当に満足です。 – Philipp

+0

@Philipp私はシステムを意図しているので、ユーザーはタスク領域を定義し、どの変数が各タスクにとって特別な関心事であるかを宣言するという点でのみ、通常のプログラムとは異なるプログラムを書くべきです。これらの変数は、Wrapper テンプレートを使用してラップする必要があります。これはオプションのコンパイル時および実行時のチェックをサポートします。したがって、私はユーザーにコードをさらに複雑にすることを強いられません。代わりに私はそれを隠したいと思う。そして当分の間、私はブーストを避けたいと思います。 – Diggy

+0

@perreal基本的に、タスクの実行が開始されると、関連する各バッファから単一のオブジェクトを取得する必要があります。たとえば、* GetBufferPtr *関数の* some_way_of_cast *。ランタイムはデータそのものを気にする必要はありませんが、私はバッファ参照の任意の数があり、各バッファには任意の種類のデータが格納されていると思います。私はタスククラスでこれをエンコードする方法を探しています。 – Diggy

答えて

1

私の経験では、ユーザタイプがユーザコードに保持されている場合、バッファを処理する実行時システムは、これらのバッファの実際のタイプについて心配する必要はありません。ユーザーは、型付きバッファーで操作を呼び出すことができます。

class Task { 
    private: 
     vector<void *> buffers; 
    public: 
     void AddBuffer(char* bptr) { 
      buffers.push_back((void *) bptr); 
     } 

     char *GetBufferPtr(int index) { 
      return some_way_of_cast(buffers[index]); 
     } 
     ... 
    }; 

    class RTTask: public Task { 
    /* ... */ 
    void do_stuff() { 
    Buffer<UserType1> b1; b1Id = b1.id(); 
    Buffer<UserType2> b2; b2Id = b2.id(); 

    AddBuffer(cast(&b1)); 
    AddBuffer(cast(&b2)); 
    } 
    void do_stuff2() { 
    Buffer<UserType1> *b1 = cast(GetBufferPtr(b1Id)); 
    b1->push(new UserType1()); 
    } 
}; 

これらの場合、キャストはユーザーコード内にあります。しかし、おそらくあなたは別の問題があります。また、ポインターに切り替えることができる場合は、Wrapperクラスは不要です。

+0

実際には、ユーザーはバッファーを認識していません。彼はWrapper テンプレートのみを見て、それを使って私が構築しているシステムで「特別な」役割を持つ変数を区別します。これを明確にするために質問を編集します。 – Diggy

0

必要なのは、タイプ消去と呼ばれるものです。これは、テンプレート内のタイプを非表示にする方法です。

基本的なテクニックは次のとおりです。 - 型から独立したマナーで宣言したい振る舞いを持つ抽象クラスを持っています。 - そのクラスからテンプレートクラスを派生させ、その仮想メソッドを実装します。

良いニュースは、おそらく自分自身を書く必要はありません、すでにboost::anyがあります。あなたが必要とするのは、ポインタを取得してオブジェクトを元に戻すだけで十分です。

void*で作業するのは悪い考えです。 Perrealが言及しているように、バッファを扱うコードは型を気にするべきではありません。良いことは、char*で作業することです。これは、バッファに一般的に使用されるタイプです(例:ソケットapis)。標準よりも安全な変換が可能な特殊ルールがchar*(エイリアスの規則を参照)にあります。

+0

"そのクラスからテンプレートクラスを派生させ、その仮想メソッドを実装してください。"私のメソッドはテンプレート化されているので、仮想化することはできません。これを回避する方法はありますか?そうであれば、例を挙げてください。 – Diggy

+0

仮想テンプレート化されていないメソッドを呼び出す基本クラスに、非仮想テンプレート化メソッドを持たせることができます。 –

0

これはまさにあなたの質問への答えではありませんが、私はちょうどあなたが

Wrapper<T> Read() { 

を書いた方法は、それの値で返しますミューテータメンバ関数になり、そのように、あることを指摘したかったですユーザーが例外の安全でないコードを書き込むように強制するので、良い習慣ではありません。

同じ理由で、STL stack::pop()メンバー関数は、スタックからポップされたオブジェクトではなく、voidを返します。

+0

これは有効な点ですが、あなたが指摘したように、答えではないので、コメントを使用する方が適切です。 –

関連する問題