Iterate through STL sequence and associative containers using same code? - c++

Let's say I'd like to write an algorithm that prints the value of each element in a container. The container could be a Sequence or Associative container (e.g. std::vector or std::map). In the case of a sequence, the algorithm would print the value_type. In the case of an associative type, the algorithm would print the data_type. How can I write my algorithm (only once!) so that it works with either one? Pretend that the algorithm is complex and that I don't want to repeat it for both sequence/associative versions.
For example:
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)
{
// ????
}

The difference that you have between your two function templates is not a difference between associative containers and sequences but a difference in the part of the type that is stored.
To clarify, std::set is an associative container but would work with your printSequence function; the problem with map is not the fact that it is associative, but that the value_type is a pair an you are only interested on the second part.
The simplest thing to do is to abstract the dereferencing operation.
E.g. used like this:
#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 ) );
}
Defined like this (there's a fair bit of boiler plate that's probably a boost one-liner):
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);
}
}

I've whipped up an iterator adapter based on Charles' answer. I'm posting it here in case anyone finds it useful:
#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()) );
}
This solution has the added advantage that the algorithm need not be aware of how to dereference the iterators. It is also reusable for any existing algorithm that expects a "data sequence".
I'm surprised this little critter doesn't already exist in Boost.

Related

Need a C++ map and list which contain iterators to each other

I have a custom templated container using a map and list being kept in sync. The map needs to hold MyList::const_iterator and the list needs to hold MyMap::const_iterator. The only solution I've been able to find is to pun one of the iterators, as in the example below.
Is there a proper way to forward declare this so that I don't need the ugly punning?
Runnable code available at http://coliru.stacked-crooked.com/a/a5eae03ad5090b27.
(There are definitely other approaches that could be used for the example, but that's out of scope. This is a snippet of a larger program. I'm simply trying to make this "circular" definition without UB.)
#include <iostream>
#include <list>
#include <unordered_map>
template<class ObjectT> class MyClass
{
private:
// SUMMARY: The map must contain an iterator to the list, and the list must contain an iterator to the map.
// I have not been able to figure out how to define that (circular), so I've punned an iterator to a different list for the map entry.
typedef std::list<ObjectT> PunnedList;
struct MapEntry
{
ObjectT m_object;
mutable typename PunnedList::const_iterator m_listIt; // Really a List::const_iterator, but that can't be defined.
};
typedef std::unordered_multimap<std::string, MapEntry> Map;
public:
struct ListEntry
{
typename Map::iterator m_mapIt;
const ObjectT& object() const
{
return m_mapIt->second.m_object;
}
const std::string& name() const
{
return m_mapIt->first;
}
};
private:
typedef std::list<ListEntry> List;
Map mMap;
List mList;
private:
typename List::const_iterator listiter_from_mapiter( typename Map::const_iterator& miter ) const
{
static_assert(sizeof(typename PunnedList::const_iterator) == sizeof(typename List::const_iterator));
return *(reinterpret_cast<typename List::const_iterator*>(&miter->second.m_listIt));
}
public:
typename List::const_iterator append( const std::string &name, const ObjectT& item )
{
static_assert(sizeof(typename PunnedList::const_iterator) == sizeof(typename List::const_iterator));
MapEntry entry{ item, typename PunnedList::const_iterator{} };
auto mapIter = mMap.insert({ name, entry });
mList.push_back({ mapIter });
auto iter = mList.cend();
--iter;
*(reinterpret_cast<typename List::const_iterator*>(&mapIter->second.m_listIt)) = iter;
return iter;
}
typename List::const_iterator begin() const
{
return mList.end();
}
typename List::const_iterator end() const
{
return mList.end();
}
void erase( typename List::const_iterator iter )
{
mMap.erase(iter->m_mapIt);
mList.erase( iter );
}
typename List::const_iterator find( const std::string &name ) const
{
auto range = mMap.equal_range(name);
for (auto mapIter = range.first; mapIter != range.second; ++mapIter)
{
// In the real program, there are additional criteria on the map entry, not needed for the example.
// if (mapIter is a match)
return listiter_from_mapiter(mapIter);
}
return mList.cend();
}
};
int main()
{
MyClass<int> container;
container.append("A",1);
container.append("B",2);
container.append("C",1);
std::cout << container.find("B")->object();
}
it's impossible to declare a type T that depend on a type Y which is also dependent on T. but you can use a wrapper to do that:
(it seems that you want to create a hash table in which elements are in insertion order? a common practice is to wrap the element and an iterator of a linked list.)
#include <string>
#include <list>
#include <unordered_map>
template<typename T>
class A{
struct Wrapper;
typedef std::unordered_multimap<std::string, Wrapper> Map;
typedef typename Map::const_iterator map_iter;
typedef std::list<map_iter> List;
typedef typename List::const_iterator list_iter;
struct Wrapper{
T value;
list_iter iter;
};
Map map;
List list;
public:
// do what you want
};
it works because to declare std::unordered_multimap<std::string, Wrapper>::iterator is not necessary to define Wrapper (needn't to be instantiated here).
Forward-declaring at least one of your inner classes breaks the cycle:
template<class ObjectT> class MyClass
{
public:
struct ListEntry;
private:
typedef std::list<ListEntry> List;
// Rest of the class, using List as you like
Note that the following List::const_iterator works thanks to std::list<T> not requiring T to be complete to be instantiated.

Search variable/item/attribute using STL in c++?

There is any way to search an item or attribute or variable in C++ using STL .
We can use any container of STL providing Searching time as less as possible . Container contains pair<int,int> . i would like to search a pair p(a,x) which should return all pairs X whose p.first == Xi.first and p.second != Xi.second for all i .
e.g.
Let container is unordered_set .
unordered_set< pair<int , int > > myset =
{{1,2},{1,5},{1,6},{2,4},{3,5},{4,6},{6,7},{6,8}};
if i search for p(1,5) then it should return pair(1,2),(1,6)
if i search for p(2,4) or (3,5),(6,7) then it should return NULL i.e. nothing
if i search for p(6,7) then it should return pair(6,8)
Something along the lines of
std::vector<std::pair<int, int>>
find_nonmatching_values(const std::unordered_multimap<int, int> & thing,
int key, int value) {
std::vector<std::pair<int, int>> ret;
auto range = thing.equal_range(key);
std::copy_if(range.first, range.second, std::back_inserter(ret),
[value](const std::pair<const int, int> &p)
{ return p.second != value; });
return ret;
}
Demo. Templatizing this code is left as an exercise for the reader.
Slightly more general than T.C.s version:
#include <type_traits>
#include <iterator>
template <typename T, typename InputIterator, typename OutputIterator, typename Comparator>
void find_mismatches(InputIterator first, InputIterator last,
T const& val, OutputIterator out, Comparator comp)
{
for (; first != last; ++first)
{
auto&& f = *first;
if (!comp(f.second, val))
*out++ = f;
}
}
template <typename AssociativeCont, typename OutputIterator, typename Comparator>
void find_mismatches(AssociativeCont&& rng, typename std::remove_reference<AssociativeCont>::type::value_type const& val, OutputIterator out, Comparator comp)
{
auto range = rng.equal_range(val.first);
find_mismatches(range.first, range.second, val.second, out, comp);
}
template <typename AssociativeCont, typename OutputIterator>
void find_mismatches(AssociativeCont&& rng, typename std::remove_reference<AssociativeCont>::type::value_type const& val, OutputIterator out)
{
auto range = rng.equal_range(val.first);
find_mismatches(range.first, range.second, val.second, out, std::equal_to<decltype(val.second)>());
}
Demo. Note that you could still expand this by using a template parameter that is a pointer-to-member to a value_type's member.

Implementing partial template specialization of template template parameter

I am having problems implementing the specialization of a class template that uses template template parameters. For example, I would like to write a class that is used for sorting:
template <template <typename, typename...> class container_type> struct SortTraits {
template <class comparator_type>
static void sort(container_type<size_t> &front, comparator_type comp) {
std::sort(front.begin(), front.end(), comp);
}
};
template <> struct SortTraits<std::list> {
template <class T, class comparator_type>
static void sort(std::list<T> &front, comparator_type comp) {
front.sort(comp);
}
};
Then I would call this as follows:
struct MyFunctor {
bool operator()( const size_t& a, const size_t& b ) const {
return a>b;
}
};
//! Alias template used for the type of container used to store a front
template <class T> using container_template = std::list<T>;
int main(int argc, char *argv[]) {
//! Concrete type for a front
typedef container_template<size_t> front_type;
front_type myContainer = {3,5,2,6,3,6,7};
MyFunctor mySortFunctor;
SortTraits<container_template>::sort(myContainer, mySortFunctor);
for (auto it = myContainer.begin(); it != myContainer.end(); ++it)
cout<<" "<<*it;
cout<<endl;
exit(0);
}
I use the specialization for the list as I would like to call the sort function that the std::list implements. Yet, this code doesn't work. Why the template specialization is not being found?
The error I get is:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/algorithm:3772:40: error: invalid operands
to binary expression ('std::__1::__list_iterator' and 'std::__1::__list_iterator')
difference_type __len = __last - __first;
~~~~~~ ^ ~~~~~~~
And it's because it's not finding the specialization.
Why bother with the traits class and the partial specialization at all instead of simply overloading a sort function? As the saying goes, std::less is more. (Live at Coliru)
template <typename Container>
using less = std::less<
typename std::decay<
decltype(*std::declval<Container&>().begin())
>::type
>;
template<typename Container, typename Compare = less<Container>>
inline void sort(Container& container, Compare&& comp = {}) {
using std::begin;
using std::end;
std::sort(begin(container), end(container), std::forward<Compare>(comp));
}
template<typename... T, typename Compare = less<std::list<T...>>>
inline void sort(std::list<T...>& list, Compare&& comp = {}) {
list.sort(std::forward<Compare>(comp));
}
For that matter, a generic sort function that prefers member sort when it exists would save you the trouble of writing overloads at all (Live at Coliru):
namespace detail {
using std::begin;
using std::end;
template<typename Container, typename Compare>
inline void sort_(Container& container, Compare&& comp, ...) {
std::sort(begin(container), end(container), std::forward<Compare>(comp));
}
template<typename Container, typename Compare>
inline auto sort_(Container& container, Compare&& comp, int) ->
decltype(container.sort(std::forward<Compare>(comp))) {
return container.sort(std::forward<Compare>(comp));
}
template<typename Container, typename Compare = std::less<
typename std::decay<
decltype(*begin(std::declval<Container&>()))
>::type
>>
inline void sort(Container& container, Compare&& comp = {}) {
sort_(container, std::forward<Compare>(comp), 0);
}
} // namespace detail
using detail::sort;
Why not just use type parameters?:
template<typename CONTAINER>
struct SortTraits
{
template<typename COMPARATOR>
static void sort( CONTAINER& container , COMPARATOR comparator = std::less<> )
{
std::sort( std::begin( container ) , std::end( container ) , comparator );
}
};
template<typename T>
struct SortTraits<std::list<T>>
{
template<typename COMPARATOR>
static void sort( std::list<T>& list , COMPARATOR comparator )
{
list.sort( comparator );
}
};
namespace utils
{
template<typename CONTAINER , typename COMPARATOR>
void sort( CONTAINER& container , COMPARATOR comparator )
{
SortTraits<CONTAINER>::sort( container , comparator );
}
}
int main()
{
std::array<int,4> arr = { 1 , 2 , 3 , 4 };
std::list<int> list = { 1 , 2 , 3 , 4 };
std::vector<int> vec = { 1 , 2 , 3 , 4 };
utils::sort( arr );
utils::sort( list );
utils::sort( vec );
}

Function template accepting nothing less than a bidirectional iterator or a pointer

I need a function template that accepts two iterators that could be pointers. If the two arguments are random_access iterators I want the return type to be an object of
std::iterator<random_access_iterator_tag, ...> type
else a
std::iterator<bidirectional_iterator_tag, ...> type.
I also want the code to refuse
compilation if the arguments are neither a bidirectional iterator, nor a pointer. I cannot have dependency on third party libraries e.g. Boost
Could you help me with the signature of this function so that it accepts bidirectional iterators as well as pointers, but not say input_iterator, output_iterator, forward_iterators.
One partial solution I can think of is the following
template<class T>
T foo( T iter1, T iter2) {
const T tmp1 = reverse_iterator<T>(iter1);
const T tmp2 = reverse_iterator<T>(iter2);
// do something
}
The idea is that if it is not bidirectional the compiler will not let me construct a reverse_iterator from it.
Here's an example with enable_if based on iterator tags. The substitution fails if the given T doesn't have a iterator_category typedef and so that overload isn't considered during overload resolution.
Since you can't use C++11, see the reference pages for enable_if and is_same to see how you can implement it by yourself.
#include <iterator>
#include <type_traits>
#include <iostream>
#include <vector>
#include <list>
template<typename T>
typename
std::enable_if<
std::is_same<
typename T::iterator_category,
std::bidirectional_iterator_tag
>::value,
T
>::type
foo(T it)
{
std::cout << "bidirectional\n";
return it;
}
template<typename T>
typename
std::enable_if<
std::is_same<
typename T::iterator_category,
std::random_access_iterator_tag
>::value,
T
>::type
foo(T it)
{
std::cout << "random access\n";
return it;
}
// specialization for pointers
template<typename T>
T* foo(T* it)
{
std::cout << "pointer\n";
return it;
}
int main()
{
std::list<int>::iterator it1;
std::vector<int>::iterator it2;
int* it3;
std::istream_iterator<int> it4;
foo(it1);
foo(it2);
foo(it3);
//foo(it4); // this one doesn't compile, it4 is an input iterator
}
Live example.
As per #JonathanWakely's comment, we can get rid of specialization for pointers if we use std::iterator_traits. The typename T::iterator_category part then becomes
typename std::iterator_traits<T>::iterator_category
a bit simpler than previous answer, no dependency on std::enable_if:
namespace detail
{
template<class T>
T do_foo(T iter1, T iter2, std::random_access_iterator_tag t)
{
cout << "do_foo random_access" << endl;
return iter1;
}
template<class T>
T do_foo(T iter1, T iter2, std::bidirectional_iterator_tag t)
{
cout << "do_foo bidirectional" << endl;
return iter1;
}
}
template<class T>
void foo(T iter1, T iter2)
{
typename std::iterator_traits<T>::iterator_category t;
detail::do_foo(iter1, iter2, t);
}
int main (int argc, const char * argv[])
{
std::vector<int> v;
foo(v.begin(), v.end());
std::list<int> l;
foo(l.begin(), l.end());
return 0;
}
The solution also supports other iterator_categories derived from std::random_access_iterator_tag or std::bidirectional_iterator_tag (should there be any), while std::same<> checks for strict category equality.

type-erased C++ output iterator

How to erase type from output iterators as std::insert_iterator and std::back_insert_iterator? Is it possible to use boost any_iterator to do so?
#include <boost/range.hpp>
#include <boost/range/detail/any_iterator.hpp>
#include <vector>
typedef boost::range_detail::any_iterator<
int, boost::incrementable_traversal_tag, int &, std::ptrdiff_t > It;
int main()
{
std::vector<int> v;
It outIt( v.begin() ); // compiles
It inserter( std::back_inserter(v) ); // does not compile
return 0;
}
any_iterator is not designed for use with output iterators, which is what back_insert_iterator is (or, for that matter, input iterators).
back_insert_iterator is defined to inherit from iterator<output_iterator_tag, void, void, void, void> i.e. its value_type, reference_type, distance_type and pointer_type are all void, but any_iterator expects to be able to indirect through its backing iterator to a non-void value. Perhaps it would be better named any_value_iterator; but then it is a detail class template.
So I implemented my own one using Boost.
#include <boost/function_output_iterator.hpp>
#include <boost/function.hpp>
template < class T >
class AnyInserter : public boost::function_output_iterator< boost::function< void ( const T & value ) > >
{
private:
typedef typename boost::function_output_iterator< boost::function< void ( const T & value ) > > BaseType;
template < class OutIt > struct Insert
{
Insert( OutIt it ) : m_it(it) {}
void operator () ( const T & value ) { m_it++ = value; }
OutIt m_it;
};
public:
template < class OutIt >
explicit AnyInserter( const OutIt & it ) : BaseType( Insert< OutIt >(it) ) {}
};
template < class OutIt >
inline AnyInserter< typename OutIt::container_type::value_type >
makeAnyInserter( const OutIt & it )
{
return AnyInserter< typename OutIt::container_type::value_type >(it);
}