2011-02-05 50 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中并不存在。