2011-02-05 56 views
0

假設我想寫一個算法來打印容器中每個元素的值。容器可以是容器SequenceAssociative(例如,std::vectorstd::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

我想我所問的可能是不可能的。 :-( – 2011-02-05 17:36:37

回答

4

,你有你的兩個函數模板之間的區別是沒有關聯容器和順序,但在存儲類型的局部不同的差異。

爲了澄清,std::set是一個關聯容器,但可以與您的printSequence函數一起使用; map的問題不是它是關聯性的,而是value_typepair,您只對second部分感興趣。

最簡單的事情就是抽象解引用操作。

E.g.使用這樣的:

#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)); 
} 

定義如下(有鍋爐板公平一點這可能是一個提振的一行):

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)來執行相同的解引用技巧 – 2011-02-05 17:56:11

1

我已經掀起了基於查爾斯的迭代器適配器回答。我在這裏張貼的情況下,任何人發現它是有用的:

#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())); 
} 

該解決方案具有附加的優點,該算法不需要知道如何解引用迭代器。對於任何需要「數據序列」的現有算法也是可重用的。

我很驚訝這個小小動物在Boost中並不存在。