2009-11-20 2 views
0

두 개의 std :: pair 항목을 사용하고 동등성을 테스트하지만 요소의 순서는 무시하는 간단한 유틸리티 펑터를 작성하려고했습니다. 추가로 (그리고 이것은 내가 문제가되는 곳이다.) 나는 std :: pair 아이템의 컨테이너를 취하여 컨테이너에서 주어진 쌍의 인수의 멤버를 테스트하는 함수를 작성했다.STL 및 단항 함수 적응 함수를 사용하여 목록 멤버쉽 확인

/* A quick functor way to check the identity of the two items of a pair to see if each pair contains the same items regardless of order */ 
template <class T> 
class EqualPairs : public std::binary_function<T,T,bool> { 
    T arg2; 

    public: 
    explicit EqualPairs (const T& x) : arg2(x) { } 

    bool operator() (const T& arg1) { 
    bool same = false; 
    if (arg1 == arg2 || (arg1.first == arg2.second && arg1.second == arg2.first)) 
     same = true; 
    return same; 
    } 
}; 

/* checks to see if the give pair p is a member of the list of pairs l. The pairs are compared disregarding the order of the pair elements (i.e. (4,2) == (2,4)) */ 
template <class P> 
bool PairListMember (const P& p, const std::vector<P>& l) 
{ 
    std::vector<P>::iterator it; 
    it = find_if (l.begin(), l.end(), EqualPairs<P>(p)); 
    bool member_of_list = (it != l.end()) ? true : false; 
    return member_of_list; 
} 

나는 일반 컨테이너 선택할 수 있도록 깨끗한 ​​방법을 생각할 수 없었다, 그래서 지금은 컨테이너 유형으로 표준 : : 벡터를 하드 코딩. 콘테이너 유형을 generic으로 만드는 것에 대한 도움은 또한 높이 평가 될 것이지만, 지금은 위의 내용을 컴파일하고 작업하고 싶습니다. 내가 오류는 다음과 같습니다

In function ‘bool PairListMember(const P&, const std::vector<P, std::allocator<_CharT> >&)’: 

    error: expected `;' before ‘it’ 
    error: ‘it’ was not declared in this scope 

In function ‘bool PairListMember(const P&, const std::vector<P, std::allocator<_CharT> >&) [with P = std::pair<int, int>]’: 

    error: dependent-name ‘std::vector<P,std::allocator<_CharT> >::iterator’ is parsed as a non-type, but instantiation yields a type 
    note: say ‘typename std::vector<P,std::allocator<_CharT> >::iterator’ if a type is meant 

는 다음과 같은 오류에 제안 결과 만 같은 '유형 이름'을 추가하여 코드를 변경 :

error: no match for ‘operator=’ in ‘it = std::find_if [with _InputIterator = __gnu_cxx::__normal_iterator<const std::pair<int, int>*, std::vector<std::pair<int, int>, std::allocator<std::pair<int, int> > > >, _Predicate = EqualPairs<std::pair<int, int> >](((const std::vector<std::pair<int, int>, std::allocator<std::pair<int, int> > >*)l)->std::vector<_Tp, _Alloc>::begin [with _Tp = std::pair<int, int>, _Alloc = std::allocator<std::pair<int, int> >](), ((const std::vector<std::pair<int, int>, std::allocator<std::pair<int, int> > >*)l)->std::vector<_Tp, _Alloc>::end [with _Tp = std::pair<int, int>, _Alloc = std::allocator<std::pair<int, int> >](), EqualPairs<std::pair<int, int> >(((const std::pair<int, int>&)((const std::pair<int, int>*)p))))’ 

/usr/include/c++/4.2/bits/stl_iterator.h:637: note: candidates are: __gnu_cxx::__normal_iterator<std::pair<int, int>*, std::vector<std::pair<int, int>, std::allocator<std::pair<int, int> > > >& __gnu_cxx::__normal_iterator<std::pair<int, int>*, std::vector<std::pair<int, int>, std::allocator<std::pair<int, int> > > >::operator=(const __gnu_cxx::__normal_iterator<std::pair<int, int>*, std::vector<std::pair<int, int>, std::allocator<std::pair<int, int> > > >&) 

답변

3

EqualPairs 템플릿에는 몇 가지 문제가 있습니다. binary_function에서 파생되지만 operator()은 하나의 인수 만 사용하기 때문에 실제로는 binary_function이 아닙니다. EqualPairs 개체를 수정하지 않으므로 operator()을 const로 만들 수 있습니다.

다소 단순화 할 수 있다고 생각합니다.

template<class T> 
struct EqualPairs : public std::binary_function<T, T, bool> 
{ 
    bool operator()(const T& lhs, const T& rhs) const 
    { 
     return lhs == rhs || lhs.first == rhs.second && lhs.second == rhs.first; 
    } 
}; 

그런 다음 당신은 당신의 바이너리 기능과 입력 매개 변수에서 술어를 만들기 위해 std::bind1st (또는 std::bind2nd)를 사용할 수 있습니다. 또한 함수를 '하나의 라이너'로 만들면 이터레이터에 대한 임시 변수를 실제로 선언 할 필요가 없으므로 consttypename을 올바르게 입력해도 문제가되지 않습니다.

반복기 유형을 템플릿 매개 변수로 사용하여이 템플릿을보다 일반적인 형식으로 만들 수 있습니다. 이렇게하면 std::vector에 대한 의존성이 제거됩니다.

template <class Iter> 
bool PairListMember(const typename std::iterator_traits<Iter>::value_type& p, Iter first, Iter last) 
{ 
    return last != std::find_if(first, last, std::bind1st(EqualPairs<typename std::iterator_traits<Iter>::value_type>(), p)); 
} 
+0

고맙습니다. 하나의 질문이지만 - PairListMember (...)을 명시 적으로 호출하지 않고 템플릿에 Iter가 설정되고 유형을 제공하는 방법은 무엇입니까? 나는 std :: iterator_traits에 익숙하지 않다. 정말 멋지다. – Shamster

+1

'std :: iterator_traits'는 유형을 다른 유형으로 맵핑 할 수 있도록 고안된 '특성'템플리트입니다. 이터 레이 터 유형을 반복하는 유형에 맵핑하려는 경우와 같이 상황을 주로 사용합니다.이 표준은 포인터 유형과 표준 컨테이너의 반복자에 대한 전문화를 제공하므로 모두 예상대로 작동하지만 사용자 정의 반복자는 선택적으로 'std :: iterator'전문화에서 파생하여 전문화를 제공해야합니다. –

+0

템플릿 인수와 함수 인수의 순서를 쳐다 보았을 때 템플릿 형식이 왼쪽에서 오른쪽 순서가 아닌 순서로 추측되고 있다고 가정해야합니다. 어떤 템플릿 인자도 제공하지 않고'PairListMember'를 실행할 수 있습니다.'Iter' 타입이'Iter first'와'Iter last' 인자에서 추론되고,'p' 타입에 적용될 것입니까? – Shamster

5

컴파일러 오류를 들어, 당신은 typename 키워드를 사용해야합니다 .

typename std::vector<P>::iterator it; 

iterator

는 표준 : 벡터 내에 삽입 된 형태를 가리키는 유형 이름, 즉이다. 템플릿 내에서 :: 연산자를 사용하여 typename에 액세스 할 때 typename 키워드를 사용해야하므로 컴파일러는 클래스 내의 일부 변수 또는 함수의 이름이 아니라 형식의 이름임을 알 수 있습니다.

편집 : 또한 벡터는이 경우 const이므로 const_iterator을 사용해야합니다.

typename std::vector<P>::const_iterator it;