2011-02-06 8 views
1

オーバーライドされた等価演算子を使用して同じインタフェースのテンプレート実装を比較する際に問題があります。消去と相互運用性のタイプ:C++での仮想バイナリ演算子の問題

Interface* ptr1 = ...; Interface* ptr2 = ...; 
*ptr1 == *ptr2; 

私が思いついたてきた唯一の解決策は、同一実装されたオブジェクトを比較するようにしていると、このような比較を実施することを強制することです:

class Interface { 
public: 
    virtual ~Interface() {} 
    virtual bool operator==(const Interface&) const = 0; 
}; 

template <typename T> class Impl : public Interface { 
public: 
    bool operator==(const Interface& rhs) const { 
     assert(typeid(rhs) == typeid(const Impl&)); 
     const Impl& rhsRef = static_cast<const Impl&>(rhs); 
     // ... 
    } 
}; 

この溶液中の問題は、それがあるということです私の目的にはあまりにも制限されています - 私は、さまざまな実装を比較できるようにしたいと思います。実装数が限られている場合は、ダブルディスパッチパターンを使用することができます。しかし、私の場合のImplはテンプレートなので、それは仮想関数テンプレートが必要になるため、二重派遣は、不可能です。

// This obviously doesn't work. 

class Interface { 
public: 
    virtual ~Interface() {} 
    virtual bool operator==(const Interface&) const = 0; 
    template <typename T2> virtual bool operator==(const Impl<T2>&) const = 0; 
}; 

template <typename T> class Impl : public Interface { 
public: 
    bool operator==(const Interface& rhs) const { 
     return rhs == *this; 
    } 
    template <typename T2> bool operator==(const Impl<T2>& rhs) const { 
     // ... 
    } 
}; 

は、任意の解決策はありますか?私はAnyIteratorクラスを書く必要があります。これはSTLイテレータをラップすることができます。それらは、異なるタイプの周りに巻かれている場合でも、私は例のイテレータとconst_iteratorのために、AnyIteratorsを比較することはできません。

std::list<int>::iterator it1 = ...; std::list<int>::const_iterator it2 = ...; 
AnyIterator<const int> myIter1 = it1; AnyIterator<const int> myIter2 = it2; 
it1 == it2;   // This works perfectly. 
myIter1 == myIter2; // This doesn't work! 

答えて

1

私はここでの問題は、あなたのインターフェイスでoperator==を持つことだけでは何の意味も持たないことだと思いますすべて。あなたの実装の比較を提供したい場合は、それは次のように、別の問題です。その場合でもために

bool operator==(const Impl<T>& other) const { 
    // ... 
} 

、しかし、私は一般的にオペレータのオーバーロードを作成思いとどまらでしょう。その代わりに、アクセサを用意して、誰かが比較したいと思うかもしれない関連属性を取得し、自分のコードを使用して誰かが作成したい比較を作成するようにしてください。

これらの任意の比較の具体的な使用例はありますか?

+0

前のセクションで書いたように、別のSTLイテレータをラップしたAnyIteratorsを比較するには、これが必要です。 AnyIteratorにはイテレータインターフェイスへのポインタが含まれています。イテレータは、保持しているSTLイテレータのタイプによって異なる実装が可能です。だから私はインターフェイスのoperator ==を宣言せずに比較を実装する可能性はないと思う。 – lizarisk

+0

@lizarisk:2つの 'std :: vector :: iterator'を比較することはできません。彼らは同じベクトルを指し示す必要があります。 2つのコンテナのイテレータを比較するのはUBです。このような機能を追加する必要がある場合は、元のコンテナを保存する必要があります。 'void *'として格納すると、両方のイテレータが同じコンテナから来ているかどうかをまず調べることができます。そうであれば、とにかく基本型は1つだけです。そうでなければ、すぐに 'false'を返します。 – MSalters

0

static_castの代わりにdynamic_castを使用し、std::bad_castをチェックすることができます(その場合は常にfalseを返します)。参照キャストの代わりにポインタdynamic_castを使うことができます。その場合、例外をキャッチする代わりにNULLをチェックするだけです。

+0

問題は、すべての可能なrhs型を渡すことができないということです。これはテンプレートなので、テンプレート引数を*から推測する方法がありません。 – lizarisk