2011-02-05 2 views
0

컨테이너의 각 요소 값을 인쇄하는 알고리즘을 작성하고 싶습니다. 컨테이너는 Sequence 또는 Associative 컨테이너 (예 : std::vector 또는 std::map) 일 수 있습니다. 시퀀스의 경우 알고리즘은 value_type을 인쇄합니다. 연관 유형의 경우 알고리즘은 data_type을 인쇄합니다. 알고리즘 (한 번만!)을 작성하여 둘 중 하나와 함께 작동하도록하려면 어떻게해야합니까? 알고리즘이 복잡하고 시퀀스/연관 버전 모두에 대해 알고리즘을 반복하고 싶지 않은 척하십시오. 예를 들어동일한 코드를 사용하여 STL 시퀀스 및 연관 컨테이너를 반복합니까?

:

template <class Iterator> 
void printSequence(Iterator begin, Iterator end) 
{ 
    for (Iterator it=begin; it!=end; ++it) 
     std::cout << *it; 
} 

template <class Iterator> 
void printAssociative(Iterator begin, Iterator end) 
{ 
    for (Iterator it=begin; it!=end; ++it) 
     std::cout << it->second; 
} 

template <class Iterator> 
void printEither(Iterator begin, Iterator end) 
{ 
    // ???? 
} 
+1

내가 원하는 것은 불가능할 수도 있습니다. :-( –

답변

4

당신이 당신의 두 기능 템플릿 사이에있는 차이는 연관 컨테이너 및 시퀀스 만 저장되는 형태의 부분의 차이의 차이가 아닙니다.

명확히하기 위해 std::set은 연관 컨테이너이지만 printSequence 함수와 함께 작동합니다. map의 문제는 연관성이 있다는 사실이 아니지만 value_typesecond 부분에만 관심이있는 pair입니다.

가장 간단한 작업은 역 참조 연산을 추상화하는 것입니다.

예. 이처럼 사용할 : 나는 반복자 어댑터 찰스를 기반으로 '를 채찍질 한

template< class ReferenceType, class IteratorType > 
struct SimpleDereference 
{ 
    ReferenceType operator() (IteratorType i) const 
    { 
     return *i; 
    } 
}; 

template< class ReferenceType, class IteratorType > 
struct MapDereference 
{ 
    ReferenceType operator() (IteratorType i) const 
    { 
     return i->second; 
    } 
}; 

// Helper template function to make an appropriate SimpleDerefence instance 
template< class Container > 
SimpleDereference< typename Container::const_reference 
       , typename Container::const_iterator > 
MakeSimpleDereference(const Container&) 
{ 
    return SimpleDereference< typename Container::const_reference 
          , typename Container::const_iterator >(); 
} 

// Helper template function to make an appropriate SimpleDerefence instance 
template< class Container > 
SimpleDereference< typename Container::reference 
       , typename Container::iterator > 
MakeSimpleDereference(Container&) 
{ 
    return SimpleDereference< typename Container::reference 
          , typename Container::iterator >(); 
} 

// Helper template function to make an appropriate MapDerefence instance 
template< class Container > 
MapDereference< const typename Container::mapped_type& 
       , typename Container::const_iterator > 
MakeMapDerefence(const Container&) 
{ 
    return MapDereference< const typename Container::mapped_type& 
         , typename Container::const_iterator >(); 
} 

// Helper template function to make an appropriate MapDerefence instance 
template< class Container > 
MapDereference< typename Container::mapped_type& 
       , typename Container::iterator > 
MakeMapDereference(Container&) 
{ 
    return MapDereference< typename Container::mapped_type& 
         , typename Container::iterator >(); 
} 

#include <iostream> 
#include <ostream> 

template <class Iterator, class Dereference> void printEither(Iterator begin, Iterator end, Dereference deref) 
{ 
    for (; begin != end; ++begin) 
    { 
     std::cout << deref(begin); 
    } 
} 
+0

+1 멋져요. 같은 참조 해제 트릭을 수행하기 위해 반복기 어댑터 (ala boost)를 쓸 수있는 것 같습니다. –

+0

두 번째'test' 함수에서 약간의 복사 - 붙여 넣기 오류가 발생했습니다. 'vec'. –

+0

@EmileCormier : 더 쉽게 호출 할 수 있도록 다시 완전히 업데이트했습니다. 이번에는 컴파일해야합니다. –

1

: (아마 부스트 한 줄의 보일러 플레이트의 공정한 비트가있다)과 같이 정의

#include <map> 
#include <vector> 

template< class X, class Y > 
void test(const std::map<X, Y>& mp) 
{ 
    printEither(mp.begin(), mp.end(), MakeMapDerefence(mp)); 
} 

template< class Y > 
void test(const std::vector<Y>& vec) 
{ 
    printEither(vec.begin(), vec.end(), MakeSimpleDereference(vec)); 
} 

대답. 나는 경우 누구라도 여기를 게시하고있어 유용 발견 :

#include <iostream> 
#include <map> 
#include <vector> 
#include <boost/iterator/iterator_adaptor.hpp> 

//------------------------------------------------------------------------------ 
template <class Iterator> 
void print(Iterator begin, Iterator end) 
{ 
    for (Iterator it=begin; it!=end; ++it) 
     std::cout << *it << "\n"; 
} 


//------------------------------------------------------------------------------ 
template <class BaseIterator> 
class MapDataIterator : 
    public boost::iterator_adaptor< 
     MapDataIterator<BaseIterator>, 
     BaseIterator, 
     typename BaseIterator::value_type::second_type > 
{ 
public: 
    typedef typename BaseIterator::value_type::second_type& reference; 

    MapDataIterator() {} 

    explicit MapDataIterator(BaseIterator base) 
    : MapDataIterator::iterator_adaptor_(base) {} 

private: 
    friend class boost::iterator_core_access; 
    reference dereference() const 
     {return this->base_reference()->second;} 
}; 

//------------------------------------------------------------------------------ 
int main() 
{ 
    std::vector<int> vec; 
    vec.push_back(31); 
    vec.push_back(41); 
    std::map<int,int> map; 
    map[31] = 41; 
    map[59] = 26; 

    typedef MapDataIterator< std::map<int,int>::iterator > DataIter; 
    print(vec.begin(), vec.end()); 
    print(DataIter(map.begin()), DataIter(map.end())); 
} 

이 솔루션은 알고리즘이 인식되지 않을 필요는 추가 된 장점을 가지고 어떻게 반복자를 역 참조한다. "데이터 시퀀스"를 예상하는 기존 알고리즘에 대해서도 재사용 할 수 있습니다.

나는이 작은 동물이 부스트에 이미 존재하지 않는다는 것에 놀랐다.

관련 문제