2012-06-29 5 views
2

STL 컬렉션을 통해 일반적으로 반복하고 키 저장 방법에 관계없이 키 값을 얻기위한 기술을 보여주는 다음 코드를 작성했습니다. 하나는 set<int>이고 다른 I가 *it에 작용하고자하는 첫 번째 경우와 초이므로 map<int, int>이다C++ STL 컬렉션에서 일반 key_type 얻기

이 컨텍스트는 I 둘 개의 모음에 동일한 기능을 제공 두 함수 리팩토링 오전이며 it->first에 (it이 const_iterator를합니다.) 중요한 것은

, 나는 컬렉션이 상당히 크다고이기 때문에이 작업을 수행 할 수 나는 단순히 그래서 만 처리 할 수있는 map에서 set을 만들어야 할 싶지 않아 하나의 특정 유형.

#include <map> 
#include <set> 
#include <iostream> 

using namespace std; 

// General case for obtaining from, say, a set. 
template< typename T > 
const typename T::key_type getKey(const typename T::const_iterator& it) 
{ 
    return *it; 
} 

// Specific case for a map<int,int> 
template<> 
const map<int, int>::key_type getKey< map<int, int> >(const map<int, int>::const_iterator& it) 
{ 
    return it->first; 
} 

template< typename T > 
void dumpOut(T& coll) 
{ 
    for (typename T::const_iterator it = coll.begin(); it != coll.end(); ++it) 
    { 
     const typename T::key_type& a = getKey<T>(it); 
     cout << a << endl; 
    } 
} 

int main() 
{ 
    set<int> s1; 
    s1.insert(10); 
    s1.insert(15); 
    s1.insert(20); 

    dumpOut< set<int> >(s1); 

    map<int, int> m1; 
    m1.insert(pair<int, int>(11, -1)); 
    m1.insert(pair<int, int>(16, -1)); 
    m1.insert(pair<int, int>(21, -1)); 

    dumpOut< map<int, int> >(m1); 

    return 0; 
} 

내 질문은 : 그것은 접근이 명확 관계없이 키와 값이 실제로 무엇인지, 일반적으로 map 위해 일하는 것이기 때문에 좀 더 일반적인 map<int,int>에 대한 전문적인 케이스를 만드는 것이 가능하다.

모든 포인터 (의도 한 장난 없음)가 유용합니다. 학술적 관점에서 사용하는 솔루션에 관심이 있지만 C++ 11 솔루션을 사용할 수 없습니다. 감사.

+1

하지 않음 모든 컬렉션에는 key_types가 있으므로이 방법을 일반적으로 어떻게 수행 할 수 있는지 알지 못합니다. – juanchopanza

+0

@ juanchopanza : 죄송합니다, 당신 말이 맞아요. 제가 진정으로 의미하는 바는 associative * collection이었습니다. * 제네릭 *으로, "제 경우에는 충분히 일반화"를 의미했습니다. :) –

답변

2

여기서 한 가지 C++ 언어 문제가 있습니다. 함수의 부분적 특수화는 허용되지 않습니다. 는 그래서이 같이 간단 할 수 없습니다

클래스 다행히도 부분 특수화가 허용됩니다
// Specific case for a map<int,***> 
template<typename Value_, typename Comp_, typename Alloc_> 
const typename map<int, Value_, Comp_, Alloc_>::key_type getKey< map<int, Value_, Comp_, Alloc_> >(const typename map<int, Value_, Comp_, Alloc_>::const_iterator& it) 
{ 
    return it->first; 
} 

- 이러한 방식으로 변경 : 나는 거기 변경된 예를 복사

// work - for let say - sets 
template <class Type_> 
struct Key { 
    Key(typename Type_::const_iterator it) : value(*it) {} 
    typename Type_::key_type value; 
}; 

// work - for map<***> 
template <class Key_, class Value_, class Comp_, class Alloc_> 
struct Key<map<Key_, Value_,Comp_,Alloc_> > { 
    typedef map<Key_, Value_,Comp_,Alloc_> Type_; 
    Key(typename Type_::const_iterator it) : value(it->first) {} 
    typename Type_::key_type value; 
}; 


template< typename T > 
const typename T::key_type getKey(const typename T::const_iterator& it) 
{ 
    return Key<T>(it).value; 
} 

: http://ideone.com/tE2aC

1

외부에서 정의 할 수있는 특성을 정의해야합니다. 또한 key_type을 추출하려고 시도하면 def_type이 true가 아닌 경우 key_type을 추출하려고합니다 (나중에 특수화 될 수있는 기본 경우보다). 이 SFINAE 및 템플릿 마법의 스냅이 필요합니다

//// This is a SFINAE context enabler. If T is defined R is returned 
template<class T, class R=void> struct enable_if_type 
{ 
    typedef R type; 
}; 

//// Default case is undefined as you want to get an error if you try to get a key_type from something that has none 
template<class T, class Enable=void> struct key_type_of; 


//// If T::key_type is a valid expression, extract it 
template<class T> 
struct key_type_of< T 
        , typename enable_if_type< typename T::key_type>::type 
        > 
{ 
    typedef typename T::key_type type; 
}; 

는 이제 key_type의 형식 정의와 모든 유형이 사용됩니다, 다른 하나는 컴파일되지 않습니다하지만 당신은 을 key_type_of의 전문화가 성공적으로 경기를 제공하는 데 사용할 수 있습니다.

예 :이 작업이 완료되면

http://ideone.com/3PxJm

, 실제로 key_type를 얻을하는 데 사용할 수 있습니다. 컨테이너 자체에서 키 자체를 추출하려면 외부 키 key_of 함수를 만들어 광범위한 유형의 컬렉션을 일반화 할 수 있습니다.

+0

고마워, 이거 꽤 영리하지만 내 상황에서는 나에게 익숙하지 않다. 이미 저에게 흥미로운 두 인스턴스에서 key_type을 얻을 수 있습니다.'map '의 특수한 경우를'map '에 대한보다 일반적인 경우로 바꾼 접근 방식을 만드는 데 관심이 있습니다. –