2011-10-28 5 views
2

いくつかのコンテキスト:(私は複雑なデータを処理するモジュールを持っていますが、それのいくつかのセマンティクスを知っていなければなりません。データはパケットと見なすことができます:モジュールは不透明なペイロード文字列についてのみ解釈する必要がありますが、最終的にはより多くの情報を必要とする人にすべてを渡します。しかし、それはいくつかの未知のパケット情報について...「バンドル」のパケットに持っているので、私はこの思い付いた:今多型(純粋抽象)マップキーは型の安全性を犠牲にしますか?

struct PacketInfo { 
    virtual void operator==(PacketInfo const&) const = 0; 
    virtual void operator<(PacketInfo const&) const = 0; 
    virtual ~PacketInfo() {} 
}; 

class Processor { 
    private: 
    template <typename T> struct pless { 
     bool operator()(T const* a, T const* b) const { 
     assert(a && b); 
     return *a < *b; 
     } 
    }; 
    // this is where the party takes place: 
    std::map<PacketInfo const*,X,pless<PacketInfo> > packets; 
    public: 
    void addPacket(PacketInfo const*,X const&); 
}; 

、アイデアは、ユーザーが自分のPacketInfoセマンティクスを実装し、渡すこと、であることによって私のクラス。例えば:私はstatic_castほとんどの人がdynamic_castを使用しますが、RTTIは、プロジェクト・ポリシーとして非アクティブ化される使用時点で
(応答する前に、慎重に質問の終わりをお読みください)

struct CustomInfo : public PacketInfo { 
    uint32_t source; 
    uint32_t dest; 
    void operator==(PacketInfo const& b) const { 
    return static_cast<CustomInfo const&>(b).dest == dest 
    && static_cast<CustomInfo const&>(b).source == source; 
    } 
    // operator< analogous 
}; 

。もちろん私は自分のタイプ情報を醸造することができますが、私は前にこれを行っていますが、それはここでは問題ではありません。

質問:タイプセーフティーを犠牲にすることなく、つまりキャストせずに、自分が望むもの(コンテンツを知らずに地図キーを持つこと)を得るにはどうすればよいですか?私はProcessorクラスを非テンプレート型にしたいと思っています。

答えて

1

完全な一般性の回答には、二重発送が必要です。あなたがn異なるサブクラスPacketInfoを持っている場合、比較演算子のn * (n - 1)/2実装が必要であるという考えがあります。実際、CustomInfoAwesomePersonalInfoを比較するとどうなりますか?これには、事前に階層全体を知り、サンプルコードはthis SO questionに表示されます。

あなたが確実な場合は、内部同じ種類のマップを適用することができる(したがって、あなたが唯一nオペレータの実装を必要とする特定のある)、次いでmap<PacketInfo, X>を有するにも意味がありません。ちょうどmap<ConcretePacketInfo, X>を使用してください。

これを行うにはいくつかの方法があります。ここで行う最も簡単な方法は、Processorをパケットタイプにテンプレート化することです。おそらくBasicProcessorクラスから継承させることができます。

別の安価な解決策は以下の通りです:あるように、コードを維持するが、Processorのみ関連addPacketを定義するテンプレートを作成:

class BasicProcessor 
{ 
private: 
    template <typename T> struct pless 
    { 
     bool operator()(T const* a, T const* b) const 
     { 
      assert(a && b); 
      return *a < *b; 
     } 
    }; 

protected: 
    std::map<PacketInfo const*, X, pless<PacketInfo>> packets; 
}; 

// You only need these lines in a public header file. 
template <typename Packet> 
class Processor : public BasicProcessor 
{ 
public: 
    void addPacket(Packet const* p, X const& x) 
    { 
     this->packets[p] = x; 
    } 
}; 

これは、呼び出し側がProcessor<CustomPacket>オブジェクトを操作するだけで追加することを保証します正しいパケットタイプ。私の意見では、Processorクラスはテンプレートクラスでなければなりません。

このメソッドの名前はThin Template Idiomで、基本的な実装はタイプセーフではありません(テンプレートに対してコードが膨らむのを防ぐため)が、インターフェイスレベルで型の安全性を復元するための薄いレイヤーを追加します。

+0

まず、 'PacketInfoChild1'は' PacketInfoChild2'と比較する必要はありません。マップには、常に同じ派生型のキーのみが含まれている必要があります。第二に、 'Processor'は' ConcretePacketInfo'がどのように見えるかを知りません。それは何もしません。 ...私はモジュールの分離にかなり関心があります... – bitmask

+0

@bitmask:基本クラスのすべてのテンプレートプロセッサに共通コードを因数分解するか、またはプロセッサクラスへのベースポインタを提示し、マップを保持するテンプレート媒介オブジェクトを持つことができますプライベートオブジェクトとして。ポイントは、マップが比較が意味をなさない特定の型を処理する必要があることです。 'addPacket'メソッドも固有でなければなりません。 –

+0

しかし私はまだヘッダーに私の 'Processor'ロジックの大部分(ほとんどすべて)を持っています。もちろん、 'Processor'をテンプレート化することで問題は解決しますが、避けたい解決策です。 – bitmask

0

私が見ている最も明白な問題は、あなたのoperator<operator== 関数はconstではないということです。したがって、 constまたはconstへの参照へのポインタを使用して呼び出すことはできません。彼らは、次のようになります。また

virtual voie operator==(PacketInfo const& other) const = 0; 
virtual voie operator<(PacketInfo const& other) const = 0; 

、論理的に、あなたはこれらの2を定義した場合、あなたは他の 4を定義する必要があります。私は通常これを処理します方法は、値そのthisオブジェクトが他のオブジェクトよりも、より少ない等しい又は 大きいか否かに応じ<==、又は> 0、 を返し多型 メンバ関数compareを定義することです。このようにして、派生したクラスは実装する関数が1つしかありません( )。

また、あなたは間違いなくあなたがそれらを比較する(とそうでないときは、比較の注文方法) をしているとき、両方のオブジェクトが同じ型を持っていることを保証するために ために、いくつかのRTTIの種類、または二重派遣を必要とします。

+0

申し訳ありません質問を入力するときに修飾子を忘れました(今修正しました)。私は、あなたが 'ボイ 'を'ボイド'にすることを意味するのと同じくらい 'const'であることを意味しました。また、 '' pless''を使うように言ったので、mapは '<'以外の比較については気にしません。実際のポイントは、たとえ私がRTTIを持っていても、私はまだ物を投げなければならないということです。 – bitmask

+0

@bitmaskあなたはまだそのものをキャストする必要があります。違いは 'dynamic_cast'は安全だということです。他の人はそうではありません。 –

2

できません。コンパイル時に型を知っているか、実行時に型をチェックします。銀色の弾丸はありません。

関連する問題