2010-05-21 6 views
2

중첩 반복기 클래스가 포함 된 여러 클래스 템플릿을 작성하여 동등한 비교가 필요합니다. 필자가 생각하기에 비회원 (친구가 아닌) operator== 기능을 사용하여 비교를 수행합니다. 이렇게, 내 컴파일러 (나는 깃발 -O3 -g -Wall Mingw32 GCC 4.4 사용하고 있습니다) 함수를 찾는 데 실패하고 가능한 이유가 부족합니다.중첩 템플릿 클래스에 대한 C++ 비 멤버 함수

아래의 다소 큰 코드 블록에는 Base 클래스, Base 객체를 포함하는 Composed 클래스 및 Outered 클래스 내에 중첩 된 것을 제외하고 Composed 클래스와 동일한 중첩 클래스가 있습니다. 비회원 operator== 기능이 각각 제공됩니다. 이러한 클래스는 템플릿이있는 형식과 템플릿이없는 형식 (고유 한 네임 스페이스)으로되어 있으며, 서명되지 않은 정수를 전문으로 사용하는 형식과 동일합니다.

main에는 각 클래스에 대해 두 개의 동일한 개체가 비교됩니다. 템플릿이 작성되지 않은 경우에는 문제가 없지만 템플릿 경우에는 컴파일러가 operator==을 찾지 못합니다. 무슨 일이야? 당신이 운영자 &를 과부하하지 않은 경우

#include <iostream> 

namespace templated { 

template<typename T> 
class Base { 
    T t_; 
public: 
    explicit Base(const T& t) : t_(t) {} 

    bool 
    equal(const Base& x) const { 
    return x.t_==t_; 
    } 
}; 

template<typename T> 
bool 
operator==(const Base<T> &x, const Base<T> &y) { 
    return x.equal(y); 
} 

template<typename T> 
class Composed { 
    typedef Base<T> Base_; 
    Base_ base_; 
public: 
    explicit Composed(const T& t) : base_(t) {} 
    bool equal(const Composed& x) const {return x.base_==base_;} 
}; 

template<typename T> 
bool 
operator==(const Composed<T> &x, const Composed<T> &y) { 
    return x.equal(y); 
} 

template<typename T> 
class Outer { 
public: 
    class Nested { 
    typedef Base<T> Base_; 
    Base_ base_; 
    public: 
    explicit Nested(const T& t) : base_(t) {} 
    bool equal(const Nested& x) const {return x.base_==base_;} 
    }; 
}; 

template<typename T> 
bool 
operator==(const typename Outer<T>::Nested &x, 
    const typename Outer<T>::Nested &y) { 
    return x.equal(y); 
} 

} // namespace templated 

namespace untemplated { 

class Base { 
    unsigned int t_; 
public: 
    explicit Base(const unsigned int& t) : t_(t) {} 

    bool 
    equal(const Base& x) const { 
    return x.t_==t_; 
    } 
}; 

bool 
operator==(const Base &x, const Base &y) { 
    return x.equal(y); 
} 

class Composed { 
    typedef Base Base_; 
    Base_ base_; 
public: 
    explicit Composed(const unsigned int& t) : base_(t) {} 
    bool equal(const Composed& x) const {return x.base_==base_;} 
}; 

bool 
operator==(const Composed &x, const Composed &y) { 
    return x.equal(y); 
} 

class Outer { 
public: 
    class Nested { 
    typedef Base Base_; 
    Base_ base_; 
    public: 
    explicit Nested(const unsigned int& t) : base_(t) {} 
    bool equal(const Nested& x) const {return x.base_==base_;} 
    }; 
}; 

bool 
operator==(const Outer::Nested &x, 
    const Outer::Nested &y) { 
    return x.equal(y); 
} 

} // namespace untemplated 

int main() { 
    using std::cout; 
    unsigned int testVal=3; 
    { // No templates first 
    typedef untemplated::Base Base_t; 
    Base_t a(testVal); 
    Base_t b(testVal); 

    cout << "a=b=" << testVal << "\n"; 
    cout << "a==b ? " << (a==b ? "TRUE" : "FALSE") << "\n"; 

    typedef untemplated::Composed Composed_t; 
    Composed_t c(testVal); 
    Composed_t d(testVal); 

    cout << "c=d=" << testVal << "\n"; 
    cout << "c==d ? " << (c==d ? "TRUE" : "FALSE") << "\n"; 

    typedef untemplated::Outer::Nested Nested_t; 
    Nested_t e(testVal); 
    Nested_t f(testVal); 

    cout << "e=f=" << testVal << "\n"; 
    cout << "e==f ? " << (e==f ? "TRUE" : "FALSE") << "\n"; 
    } 
    { // Now with templates 
    typedef templated::Base<unsigned int> Base_t; 
    Base_t a(testVal); 
    Base_t b(testVal); 

    cout << "a=b=" << testVal << "\n"; 
    cout << "a==b ? " << (a==b ? "TRUE" : "FALSE") << "\n"; 

    typedef templated::Composed<unsigned int> Composed_t; 
    Composed_t c(testVal); 
    Composed_t d(testVal); 

    cout << "c=d=" << testVal << "\n"; 
    cout << "d==c ? " << (c==d ? "TRUE" : "FALSE") << "\n"; 

    typedef templated::Outer<unsigned int>::Nested Nested_t; 
    Nested_t e(testVal); 
    Nested_t f(testVal); 

    cout << "e=f=" << testVal << "\n"; 
    cout << "e==f ? " << (e==f ? "TRUE" : "FALSE") << "\n"; 
    // Above line causes compiler error: 
    // error: no match for 'operator==' in 'e == f' 
    } 

    cout << std::endl; 
    return 0; 
} 
+0

이 질문은 C++에서 템플릿 이름 조회와 관련있는 것처럼 보입니다. 나는 이것이 합리적으로 공통적 인 하위 주제 인 것으로 보이지만 이름 검색 태그를 추가하려고 시도했지만 명성이 부족한 초보자였습니다. 그런 태그를 대신 추가하는 사람이 더 평판이 좋습니까? – beldaz

답변

5

문제는 템플릿이있는 중첩 클래스에서 상당히 일반적입니다.

template <class T> 
struct Outer { struct Inner {}; }; 

template <class T> 
void increment(typename Outer<T>::Inner&) {} 

increment 기능을 찾을 수 없습니다. 나는 컴파일러가 해결하기가 너무 어렵다고 생각한다.

당신은 비록 문제를 완화 할 수

namespace detail 
{ 
    template <class T> struct InnerImpl {}; 

    template <class T> void increment(InnerImpl&) {} 
} 

template <class T> 
struct Outer 
{ 
    typedef detail::InnerImpl<T> Inner; 
}; 

int main(int argc, char* argv[]) 
{ 
    Outer<int>::Inner inner; 
    increment(inner);   // works 
} 

재미, 그렇지?

무료 메서드의 인수 (결과 형식이 아님)의 typename은 일반적으로 빨간색 청어이며 자동 인수 차감을 방지하는 것으로 보입니다.

+0

고마워 Matthieu - 나는 분명하고 잘 쓰여진 당신의 대답을 가지고 갈 것입니다. 표준에서 더 결정 론적 일 수있는 엄격한 규칙이나 지침이 있었으면 좋겠지 만 엄지 손가락의 규칙이 좋은 것처럼 보입니다.그것은 조금 불만족 스럽지만 언어에 관한 것이지 당신의 대답이 아닙니다. – beldaz

+0

불행히도 나는 표준이 아니기 때문에 필요할 때마다 표준을 인용 할 수 없다는 것을 의미한다. AndreyT와 같은 일부 회원은 아마도 존재하는 경우 정확한 인용구를 찾을 수 있지만,주의를 끌어들이는 실제적인 방법은 없다. 다른 질문에 대한 대답 중 하나에 의견을 게시하는 것 ... 이것은 매우 무례합니다. 나는 사적인 메시지를 전하고자한다.) –

0

후 바로 메모리 주소를 비교합니다. 이것을 할 필요가 없습니다.

+0

평등을 비교하는 것이 메모리 주소를 비교하는 것만큼이나 쉽다면, 우리는 훨씬 빨리 생각했을 것입니다. –

+0

신속한 해결 방법이 아닌 문제에 대한 통찰력을 찾고 있습니다. 또한 이터레이터의 경우 가장 중요한 비교는 메모리 주소 비교가 자주 적합하지 않은 시퀀스의 end()와 비교됩니다. – beldaz

0

답변을 수락 한 후 최소한의 노력으로 코드를 수정하는 것이 최선의 방법이라고 생각했습니다. 문제의 명확한 아이디어로 무장 한 나는 C++ FAQ에서 새로운 영감을 얻었고 비회원 인 operator==을 친구 기능으로 클래스 정의에 병합했습니다. 이것은 소리가 나는 것만 큼 큰 해킹이 아닙니다. 멤버 함수를 제공하는 이유는 친구가 필요하지 않기 때문입니다. 그러나 템플릿의 경우 friend 함수는 함수 정의가 따라서 조회 문제를 피할 수 있습니다.

template<typename T> 
class Outer { 
public: 
    class Nested { 
    typedef Base<T> Base_; 
    Base_ base_; 
    friend bool operator==(Nested const &x, Nested const &y) { 
     return x.base_==y.base_; 
    } 
    public: 
    explicit Nested(const T& t) : base_(t) {} 
    }; 
}; 
관련 문제