2011-02-06 4 views
1

재정의 된 동등성 연산자를 통해 동일한 인터페이스의 템플릿 구현을 비교하는 데 문제가 있습니다.지우기 및 상호 운용성 유형 : C++의 가상 이진 연산자 문제

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

I가 와서 한 유일한 솔루션은 동일하게 구현 객체를 비교할 수 있으며이 같은 비교를 구현하는 것을 강제하는 것입니다

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 { 
     // ... 
    } 
}; 

모든 솔루션은 거기에 있습니까? Any STL iterator를 래핑 할 수있는 AnyIterator 클래스를 작성해야합니다. 서로 다른 유형의 주위에 감싸 인 경우하지만 예를 들어 반복자와 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 반복자를 감싸는 AnyIterator를 비교하기 위해이 항목이 필요합니다. AnyIterator에는 iterator 인터페이스에 대한 포인터가 들어 있으며,이 포인터는 보유하고있는 STL 반복자의 유형에 따라 다르게 구현할 수 있습니다. 따라서 인터페이스에서 연산자 ==를 선언하지 않고도 비교를 구현할 수있는 가능성은 없습니다. – lizarisk

+0

@lizarisk : 두 개의 std :: vector :: iterator를 비교할 수 있다고 생각조차 할 수 없습니다. 그들은 같은 벡터를 지적해야합니다. 두 컨테이너의 반복자를 비교하는 것은 UB입니다. 이러한 기능을 추가해야하는 경우 원래 컨테이너를 저장해야합니다. 'void *'로 저장하면 두 반복자가 같은 컨테이너에서 왔는지 먼저 확인해 볼 수 있습니다. 그렇다면, 근본적인 타입은 하나 뿐이며, 그렇지 않으면 즉시'false'를 반환합니다. – MSalters

0

static_cast 대신 dynamic_cast을 사용할 수 있으며 std::bad_cast을 확인할 수 있습니다.이 경우 항상 false를 반환합니다. 참조 캐스팅 대신 포인터 dynamic_cast를 사용할 수 있습니다.이 경우 예외를 잡는 대신 NULL을 확인하기 만하면됩니다.

+0

문제는 모든 가능한 rhs 형식을 넘을 수 없다는 것입니다. 왜냐하면 템플릿이기 때문에 * 템플릿 인수를 추론 할 방법이 없습니다. – lizarisk