How can I further specialize this template idea? - c++

I can do this with a template specialization I think, for nestedness of 1,2,3 (most common cases) by respectively nesting 1,2,3 for loops and referring to the types by their typenames in stl...but for arbitrary depth, without use of the preprocessor, is there a way to do this? Maybe with mpl? Or would I need a preprocessor tool as well? Right now I am doing something like this:
template<typename T, int>
struct MapDump {};
template<typename T >
struct MapDump<T,1>
{
static void dump(const T& map, string file, string header="")
{
if (!header.empty())
cout << header << endl;
for (typename T::const_iterator cIt = map.begin();
cIt != map.end();
++cIt)
cout << cIt->first << "," << cIt->second << endl;
}
};
template<typename T >
struct MapDump<T,2>
{
static void dump(const T& map, string file, string header="")
{
if (!header.empty())
cout << header << endl;
for (typename T::const_iterator it1 = map.begin();
it1 != map.end();
++it1)
for (typename T::mapped_type::const_iterator it2 = it1->second.begin();
it2 != it1->second.end();
++it2)
cout << it1->first << "," << it2->first << "," << it2->second << endl;
}
};
which I can call with, for example:
map<int, map<int, double> > m;
m[1][1] = 1.0;
m[1][2] = 1.0;
m[2][1] = 2.0;
m[2][2] = 2.0;
MapDump< map<int, map<int, double> >, 2 >::dump(m, "test.csv");
(I stripped out the fstream stuff and left std::cout to simplify the sample code here) My question is, how can I go about specializing when, say, the last level mapped_type is a container type? For example map > is technically a 2-depth construct and not a one level construct...but my nest of 2 specialization wouldn't compile for that type...any other suggestions on how to, perhaps abstract thsi further (figure out the depth of the construct at compile time as well) are welcome..thanks!

This performs the recursion over all nested types until it reaches a
non-nested type. It uses SFINAE to detect if there is a mapped_type
member typedef (You can use BOOST_HAS_XXX to create such a helper).
What it does not yet do is do collect the key values and pass them on
to the next level. You can either collect keys in a vector and keep
passing them down or figure out the nesting depth and use an
approximate tuple (this increases compile time complexity to n^2).
Do not use decltype and the for_each loop, if you want C++03
compatibility.
#include <map>
#include <iostream>
// sfinae to detect a mapped type
template<typename T>
struct has_mapped_type
{
private:
typedef char one;
typedef struct { char arr[2]; } two;
template<typename U>
struct wrap {};
template<typename U>
static one test(wrap<typename U::mapped_type>*);
template<typename U>
static two test(...);
public:
static const bool value = sizeof(test<T>(0)) == 1;
};
template<typename T, bool has_mapped_type>
// false version
struct dump_impl {
void operator()(const T& t) const {
std::cout << t << std::endl;
}
};
template<typename T>
// true version
struct dump_impl<T, true>
: dump_impl<
typename T::mapped_type
, has_mapped_type<typename T::mapped_type>::value
>
{
void operator()(const T& t) const {
for(auto& x : t) {
dump_impl<
typename T::mapped_type
, has_mapped_type<typename T::mapped_type>::value
>::
operator()(x.second);
}
}
};
template<typename T>
struct dump : public dump_impl<T, has_mapped_type<T>::value> {
void operator()(const T& t) const {
dump_impl<T, has_mapped_type<T>::value>::operator()(t);
}
};
int main()
{
std::map<int, std::map<int, double> > m;
m[1][1] = 1.0;
m[1][2] = 1.0;
m[2][1] = 2.0;
m[2][2] = 2.0;
dump<decltype(m)>()(m);
return 0;
}

Try
template<int I>
struct Int { };
template<typename T, int I>
struct MapDump
{
static void dump(const T& map, const string& file, const string& header="") {
if (!header.empty())
cout << header << endl;
dump(map, "", Int<I>());
}
private:
template<typename Map, int I1>
static void dump(const Map& map, const string& agg, Int<I1>) {
for (typename Map::const_iterator cIt = map.begin();
cIt != map.end();
++cIt) {
dump(cIt->second, (agg + boost::lexical_cast<std::string>(
cIt->first) + ", "), Int<I1-1>());
}
}
template<typename D>
static void dump(const D& d, const string& agg, Int<0>) {
cout << agg << d << endl;
}
};

Here is a simple recursive function template that will print the nested maps:
template <typename Last>
void dumpMap(const Last &last,const std::string &first)
{
std::cout << first << last << "\n";
}
template <typename A,typename B>
void dumpMap(const std::map<A,B> &last,const std::string &first=std::string())
{
typename std::map<A,B>::const_iterator i=last.begin(), i_end=last.end();
for (;i!=i_end;++i) {
std::ostringstream s;
s << first << (*i).first << ",";
dumpMap((*i).second,s.str());
}
}
You can use it like this:
map<int, map<int, double> > m;
m[1][1] = 1.0;
m[1][2] = 1.0;
m[2][1] = 2.0;
m[2][2] = 2.0;
dumpMap(m);

Related

C++ for range loop for template class

I have a template class below that depends on 2 classes U and T
and have implemented the iterator function for both classes (see the end of this post).
I can iterate over the respective vectors of the class using iterators,
but I was wondering if it was possible to do the same using the for range loop syntax instead of using iterators.
With something like
for (auto x : myclass <double>)
{
std::cout << x << std::endl ;
}
I know it does not work but I could not manage to find the syntax if any,
Thanks in advance for your answer
#include<iostream>
#include<string>
#include<vector>
template<class U,class T>
class MyClass
{
public:
MyClass(
const std::vector<U> & vect_u ,
const std::vector<T> & vect_t )
{
m_vect_u = vect_u;
m_vect_t = vect_t;
}
~MyClass(){}
// begin()
template<class Z>
typename std::enable_if<std::is_same<Z,T>::value, typename std::vector<Z>::iterator>::type
begin() noexcept { return m_vect_t.begin(); }
template<class Z>
typename std::enable_if<std::is_same<Z,U>::value, typename std::vector<Z>::iterator>::type
begin() noexcept { return m_vect_u.begin(); }
// end()
template<class Z>
typename std::enable_if<std::is_same<Z,T>::value, typename std::vector<Z>::iterator>::type
end() noexcept { return m_vect_t.end(); }
template<class Z>
typename std::enable_if<std::is_same<Z,U>::value, typename std::vector<Z>::iterator>::type
end() noexcept { return m_vect_u.end(); }
// cbegin()
template<class Z>
typename std::enable_if<std::is_same<Z,T>::value, typename std::vector<Z>::const_iterator>::type
cbegin() const noexcept { return m_vect_t.cbegin(); }
template<class Z>
typename std::enable_if<std::is_same<Z,U>::value, typename std::vector<Z>::const_iterator>::type
cbegin() const noexcept { return m_vect_u.cbegin(); }
// cend()
template<class Z>
typename std::enable_if<std::is_same<Z,T>::value, typename std::vector<Z>::const_iterator>::type
cend() const noexcept { return m_vect_t.cend(); }
template<class Z>
typename std::enable_if<std::is_same<Z,U>::value, typename std::vector<Z>::const_iterator>::type
cend() const noexcept { return m_vect_u.cend(); }
private:
std::vector<U> m_vect_u ;
std::vector<T> m_vect_t ;
};
int main()
{
std::vector<double> vect_double = {1.5,2.5,3.5} ;
std::vector<int> vect_int = {-1,-2,-3} ;
MyClass<double,int> myclass( vect_double, vect_int);
std::cout << "iteration over int" << std::endl ;
for(auto itr = myclass.begin<int>(); itr < myclass.end<int>() ; ++itr)
{
std::cout << *itr << std::endl ;
}
std::cout << "iteration over double" << std::endl ;
for(auto itr = myclass.begin<double>(); itr < myclass.end<double>() ; ++itr)
{
std::cout << *itr << std::endl ;
}
return 0 ;
}
You might provide function to return "range" (directly std::vector or a wrapper):
template <typename Z> // Or SFINAE or if constexpr or any other implementation
auto& getVector() { return std::get<std::vector<Z>&>(std::tie(m_vect_u, m_vect_t)); }
template <typename Z>
const auto& getVector() const { return std::get<const std::vector<Z>&>(std::tie(m_vect_u, m_vect_t)); }
and then
std::cout << "iteration over int" << std::endl ;
for (auto e : myclass.getVector<int>())
{
std::cout << e << std::endl ;
}
Demo
You need an object that has non-templated begin and end. For example a class template that wraps MyClass:
template <typename Z,typename U,typename T>
struct MyClassWrapper {
MyClass<U,T>* parent;
auto begin() { return parent-> template begin<Z>(); }
auto end() { return parent-> template end<Z>();}
};
template <typename Z,typename U,typename T>
MyClassWrapper<Z,U,T> make_wrapper(MyClass<U,T>* p){
return {p};
}
Then this works:
for (auto& x : make_wrapper<int>(&myclass)){
std::cout << x << "\n";
}
for (auto& x : make_wrapper<double>(&myclass)){
std::cout << x << "\n";
}
Live Demo

no matching function for call to std::get with const tuple ref as argument

I've been trying to make a generic function in order to build a query in SQL.
In order to do that, I went and used tuple with variadic template, in order to make the query more generic.
This is the code (This is not a final code so understand some of the code is pseudo-code):
#include <tuple>
template<std::size_t I>
struct Visit_Tup_Impl
{
template<typename ...T>
static const std::string& visit_tup (const std::tuple<T...>& values, int comp)
{
if (I == comp)
{
// I know it doesn't do anything - for simplicity
std::get<I, std::tuple<T...> > (values);
return EMPTY_STRING;
}
else
{
return Visit_Tup_Impl<I-1>::visit_tup (values, comp);
}
}
};
template<>
template<>
const std::string&
Visit_Tup_Impl<0>::visit_tup (const std::tuple<>& values, int comp)
{
assert (0 && "Should not happen");
return EMPTY_STRING;
}
template <typename ...T>
std::string
create_coupled_query (const std::vector<std::string>& keys,
const std::vector<std::tuple<T...> >& values)
{
std::ostringstream local;
local << "(";
auto iter = values.begin ();
auto iter_end = values.end ();
for (; iter != iter_end; ++iter)
{
local << "(";
int i = 1;
do
{
local << keys [i] << "=" << to_sql_string (Visit_Tup_Impl<(sizeof...(T) - 1)>::visit_tup (*iter, i));
++i;
if (i < keys.size ())
local << " AND ";
}
while (i < keys.size ());
local << ")";
if (iter + 1 != iter_end)
local << " OR ";
}
local << ")";
return local.str ();
}
This is the line that wouldn't compile:
std::get<I, std::tuple<T...> > (values);
I Get This compilation error:
no matching function for call to ‘get(const std::tuple<ACE_Time_Value, ACE_Time_Value, std::basic_string<char, std::char_traits, std::allocator > >&)’
Also, it gives me suggestions for std::get candidates (under utility.h):
template<long unsigned int _Int, class _Tp1, class _Tp2> constexpr typename std::tuple_element<_Int, std::pair<_Tp1, _Tp2> >::type& std::get(std::pair<_Tp1, _Tp2>&)
and some more, which are not relevant for me.
Ur help compiling this please

Generic for_eaches template [duplicate]

With the new range-based for-loop we can write code like:
for(auto x: Y) {}
Which IMO is a huge improvement from (for ex.)
for(std::vector<int>::iterator x=Y.begin(); x!=Y.end(); ++x) {}
Can it be used to loop over two simultaneous loops, like Python's zip function? For those unfamiliar with Python, the code:
Y1 = [1, 2, 3]
Y2 = [4, 5, 6, 7]
for x1,x2 in zip(Y1, Y2):
print(x1, x2)
Gives as output (1,4) (2,5) (3,6)
Warning: boost::zip_iterator and boost::combine as of Boost 1.63.0 (2016 Dec 26) will cause undefined behavior if the length of the input containers are not the same (it may crash or iterate beyond the end).
Starting from Boost 1.56.0 (2014 Aug 7) you could use boost::combine (the function exists in earlier versions but undocumented):
#include <boost/range/combine.hpp>
#include <vector>
#include <list>
#include <string>
int main() {
std::vector<int> a {4, 5, 6};
double b[] = {7, 8, 9};
std::list<std::string> c {"a", "b", "c"};
for (auto tup : boost::combine(a, b, c, a)) { // <---
int x, w;
double y;
std::string z;
boost::tie(x, y, z, w) = tup;
printf("%d %g %s %d\n", x, y, z.c_str(), w);
}
}
This would print
4 7 a 4
5 8 b 5
6 9 c 6
In earlier versions, you could define a range yourself like this:
#include <boost/iterator/zip_iterator.hpp>
#include <boost/range.hpp>
template <typename... T>
auto zip(T&&... containers) -> boost::iterator_range<boost::zip_iterator<decltype(boost::make_tuple(std::begin(containers)...))>>
{
auto zip_begin = boost::make_zip_iterator(boost::make_tuple(std::begin(containers)...));
auto zip_end = boost::make_zip_iterator(boost::make_tuple(std::end(containers)...));
return boost::make_iterator_range(zip_begin, zip_end);
}
The usage is the same.
std::transform can do this trivially:
std::vector<int> a = {1,2,3,4,5};
std::vector<int> b = {1,2,3,4,5};
std::vector<int>c;
std::transform(a.begin(),a.end(), b.begin(),
std::back_inserter(c),
[](const auto& aa, const auto& bb)
{
return aa*bb;
});
for(auto cc:c)
std::cout<<cc<<std::endl;
If the second sequence is shorter, my implementation seems to be giving default initialized values.
So I wrote this zip before when I was bored, I decided to post it because it's different than the others in that it doesn't use boost and looks more like the c++ stdlib.
template <typename Iterator>
void advance_all (Iterator & iterator) {
++iterator;
}
template <typename Iterator, typename ... Iterators>
void advance_all (Iterator & iterator, Iterators& ... iterators) {
++iterator;
advance_all(iterators...);
}
template <typename Function, typename Iterator, typename ... Iterators>
Function zip (Function func, Iterator begin,
Iterator end,
Iterators ... iterators)
{
for(;begin != end; ++begin, advance_all(iterators...))
func(*begin, *(iterators)... );
//could also make this a tuple
return func;
}
Example use:
int main () {
std::vector<int> v1{1,2,3};
std::vector<int> v2{3,2,1};
std::vector<float> v3{1.2,2.4,9.0};
std::vector<float> v4{1.2,2.4,9.0};
zip (
[](int i,int j,float k,float l){
std::cout << i << " " << j << " " << k << " " << l << std::endl;
},
v1.begin(),v1.end(),v2.begin(),v3.begin(),v4.begin());
}
With range-v3:
#include <range/v3/all.hpp>
#include <vector>
#include <iostream>
namespace ranges {
template <class T, class U>
std::ostream& operator << (std::ostream& os, common_pair<T, U> const& p)
{
return os << '(' << p.first << ", " << p.second << ')';
}
}
using namespace ranges::v3;
int main()
{
std::vector<int> a {4, 5, 6};
double b[] = {7, 8, 9};
std::cout << view::zip(a, b) << std::endl;
}
The output:
[(4, 7),(5, 8),(6, 9)]
See <redi/zip.h> for a zip function which works with range-base for and accepts any number of ranges, which can be rvalues or lvalues and can be different lengths (iteration will stop at the end of the shortest range).
std::vector<int> vi{ 0, 2, 4 };
std::vector<std::string> vs{ "1", "3", "5", "7" };
for (auto i : redi::zip(vi, vs))
std::cout << i.get<0>() << ' ' << i.get<1>() << ' ';
Prints 0 1 2 3 4 5
You can use a solution based on boost::zip_iterator. Make a phony container class maintaining references to your containers, and which return zip_iterator from the begin and end member functions. Now you can write
for (auto p: zip(c1, c2)) { ... }
Example implementation (please test):
#include <iterator>
#include <boost/iterator/zip_iterator.hpp>
template <typename C1, typename C2>
class zip_container
{
C1* c1; C2* c2;
typedef boost::tuple<
decltype(std::begin(*c1)),
decltype(std::begin(*c2))
> tuple;
public:
zip_container(C1& c1, C2& c2) : c1(&c1), c2(&c2) {}
typedef boost::zip_iterator<tuple> iterator;
iterator begin() const
{
return iterator(std::begin(*c1), std::begin(*c2));
}
iterator end() const
{
return iterator(std::end(*c1), std::end(*c2));
}
};
template <typename C1, typename C2>
zip_container<C1, C2> zip(C1& c1, C2& c2)
{
return zip_container<C1, C2>(c1, c2);
}
I leave the variadic version as an excellent exercise to the reader.
If you like operator overloading, here are three possibilities. The first two are using std::pair<> and std::tuple<>, respectively, as iterators; the third extends this to range-based for. Note that not everyone will like these definitions of the operators, so it's best to keep them in a separate namespace and have a using namespace in the functions (not files!) where you'd like to use these.
#include <iostream>
#include <utility>
#include <vector>
#include <tuple>
// put these in namespaces so we don't pollute global
namespace pair_iterators
{
template<typename T1, typename T2>
std::pair<T1, T2> operator++(std::pair<T1, T2>& it)
{
++it.first;
++it.second;
return it;
}
}
namespace tuple_iterators
{
// you might want to make this generic (via param pack)
template<typename T1, typename T2, typename T3>
auto operator++(std::tuple<T1, T2, T3>& it)
{
++( std::get<0>( it ) );
++( std::get<1>( it ) );
++( std::get<2>( it ) );
return it;
}
template<typename T1, typename T2, typename T3>
auto operator*(const std::tuple<T1, T2, T3>& it)
{
return std::tie( *( std::get<0>( it ) ),
*( std::get<1>( it ) ),
*( std::get<2>( it ) ) );
}
// needed due to ADL-only lookup
template<typename... Args>
struct tuple_c
{
std::tuple<Args...> containers;
};
template<typename... Args>
auto tie_c( const Args&... args )
{
tuple_c<Args...> ret = { std::tie(args...) };
return ret;
}
template<typename T1, typename T2, typename T3>
auto begin( const tuple_c<T1, T2, T3>& c )
{
return std::make_tuple( std::get<0>( c.containers ).begin(),
std::get<1>( c.containers ).begin(),
std::get<2>( c.containers ).begin() );
}
template<typename T1, typename T2, typename T3>
auto end( const tuple_c<T1, T2, T3>& c )
{
return std::make_tuple( std::get<0>( c.containers ).end(),
std::get<1>( c.containers ).end(),
std::get<2>( c.containers ).end() );
}
// implement cbegin(), cend() as needed
}
int main()
{
using namespace pair_iterators;
using namespace tuple_iterators;
std::vector<double> ds = { 0.0, 0.1, 0.2 };
std::vector<int > is = { 1, 2, 3 };
std::vector<char > cs = { 'a', 'b', 'c' };
// classical, iterator-style using pairs
for( auto its = std::make_pair(ds.begin(), is.begin()),
end = std::make_pair(ds.end(), is.end() ); its != end; ++its )
{
std::cout << "1. " << *(its.first ) + *(its.second) << " " << std::endl;
}
// classical, iterator-style using tuples
for( auto its = std::make_tuple(ds.begin(), is.begin(), cs.begin()),
end = std::make_tuple(ds.end(), is.end(), cs.end() ); its != end; ++its )
{
std::cout << "2. " << *(std::get<0>(its)) + *(std::get<1>(its)) << " "
<< *(std::get<2>(its)) << " " << std::endl;
}
// range for using tuples
for( const auto& d_i_c : tie_c( ds, is, cs ) )
{
std::cout << "3. " << std::get<0>(d_i_c) + std::get<1>(d_i_c) << " "
<< std::get<2>(d_i_c) << " " << std::endl;
}
}
// declare a, b
BOOST_FOREACH(boost::tie(a, b), boost::combine(list_of_a, list_of_b)){
// your code here.
}
I ran into this same question independently and didn't like the syntax of any of the above. So, I have a short header file that essentially does the same as the boost zip_iterator but has a few macros to make the syntax more palatable to me:
https://github.com/cshelton/zipfor
For example you can do
vector<int> a {1,2,3};
array<string,3> b {"hello","there","coders"};
zipfor(i,s eachin a,b)
cout << i << " => " << s << endl;
The main syntactic sugar is that I can name the elements from each container. I also include a "mapfor" that does the same, but for maps (to name the ".first" and ".second" of the element).
If you have a C++14 compliant compiler (e.g. gcc5) you can use zip provided in the cppitertools library by Ryan Haining, which looks really promising:
array<int,4> i{{1,2,3,4}};
vector<float> f{1.2,1.4,12.3,4.5,9.9};
vector<string> s{"i","like","apples","alot","dude"};
array<double,5> d{{1.2,1.2,1.2,1.2,1.2}};
for (auto&& e : zip(i,f,s,d)) {
cout << std::get<0>(e) << ' '
<< std::get<1>(e) << ' '
<< std::get<2>(e) << ' '
<< std::get<3>(e) << '\n';
std::get<1>(e)=2.2f; // modifies the underlying 'f' array
}
For a C++ stream processing library I'm writing I was looking for a solution that doesn't rely on third party libraries and works with an arbitrary number of containers. I ended up with this solution. It's similar to the accepted solution which uses boost (and also results in undefined behavior if the container lengths are not equal)
#include <utility>
namespace impl {
template <typename Iter, typename... Iters>
class zip_iterator {
public:
using value_type = std::tuple<const typename Iter::value_type&,
const typename Iters::value_type&...>;
zip_iterator(const Iter &head, const Iters&... tail)
: head_(head), tail_(tail...) { }
value_type operator*() const {
return std::tuple_cat(std::tuple<const typename Iter::value_type&>(*head_), *tail_);
}
zip_iterator& operator++() {
++head_; ++tail_;
return *this;
}
bool operator==(const zip_iterator &rhs) const {
return head_ == rhs.head_ && tail_ == rhs.tail_;
}
bool operator!=(const zip_iterator &rhs) const {
return !(*this == rhs);
}
private:
Iter head_;
zip_iterator<Iters...> tail_;
};
template <typename Iter>
class zip_iterator<Iter> {
public:
using value_type = std::tuple<const typename Iter::value_type&>;
zip_iterator(const Iter &head) : head_(head) { }
value_type operator*() const {
return value_type(*head_);
}
zip_iterator& operator++() { ++head_; return *this; }
bool operator==(const zip_iterator &rhs) const { return head_ == rhs.head_; }
bool operator!=(const zip_iterator &rhs) const { return !(*this == rhs); }
private:
Iter head_;
};
} // namespace impl
template <typename Iter>
class seq {
public:
using iterator = Iter;
seq(const Iter &begin, const Iter &end) : begin_(begin), end_(end) { }
iterator begin() const { return begin_; }
iterator end() const { return end_; }
private:
Iter begin_, end_;
};
/* WARNING: Undefined behavior if iterator lengths are different.
*/
template <typename... Seqs>
seq<impl::zip_iterator<typename Seqs::iterator...>>
zip(const Seqs&... seqs) {
return seq<impl::zip_iterator<typename Seqs::iterator...>>(
impl::zip_iterator<typename Seqs::iterator...>(std::begin(seqs)...),
impl::zip_iterator<typename Seqs::iterator...>(std::end(seqs)...));
}
From C++23, we can iterate on std::views::zip.
Below is simple example.
#include <iostream>
#include <ranges>
#include <vector>
int main() {
std::vector<int> x {4, 5, 6};
double y[] = {7, 8, 9};
for (auto [elem1,elem2] : std::views::zip(x, y))
std::cout << "[" << elem1 << "," << elem2 << "]" << " ";
}
The output can be verified below (an online compiler). Not sure how many days the link exists.
https://godbolt.org/z/KjjE4eeGY
An improvement on aaronman's solution:
Still C++11.
No recursive template expansion.
Support for container zipping.
Utilizes the approach of Sean Parent's famed for_each_arg().
// Includes only required for the example main() below!
#include <vector>
#include <iostream>
namespace detail {
struct advance {
template <typename T> void operator()(T& t) const { ++t; }
};
// Adaptation of for_each_arg, see:
// https://isocpp.org/blog/2015/01/for-each-argument-sean-parent
template <class... Iterators>
void advance_all(Iterators&... iterators) {
[](...){}((advance{}(iterators), 0)...);
}
} // namespace detail
template <typename F, typename Iterator, typename ... ExtraIterators>
F for_each_zipped(
F func,
Iterator begin,
Iterator end,
ExtraIterators ... extra_iterators)
{
for(;begin != end; ++begin, detail::advance_all(extra_iterators...))
func(*begin, *(extra_iterators)... );
return func;
}
template <typename F, typename Container, typename... ExtraContainers>
F for_each_zipped_containers(
F func,
Container& container,
ExtraContainers& ... extra_containers)
{
return for_each_zipped(
func, std::begin(container), std::end(container), std::begin(extra_containers)...);
}
int main () {
std::vector<int> v1 { 1, 2, 3};
std::vector<int> v2 { 3, 2, 1};
std::vector<float> v3 {1.2, 2.4, 9.0};
std::vector<float> v4 {1.2, 2.4, 9.0};
auto print_quartet =
[](int i,int j,float k,float l) {
std::cout << i << " " << j << " " << k << " " << l << '\n';
};
std::cout << "Using zipped iterators:\n";
for_each_zipped(print_quartet, v1.begin(), v1.end(), v2.begin(), v3.begin(), v4.begin());
std::cout << "\nUsing zipped containers:\n";
for_each_zipped_containers(print_quartet, v1, v2, v3, v4);
}
See it working on GodBolt.
I would propose this one. I found it to be quite elegant, and exactly what I (and you) needed.
https://github.com/CommitThis/zip-iterator
Just in case here's a code copy. Note, it is distributed under MIT License, also don't forget to put name of author.
zip.hpp
/***
* MIT License
* Author: G Davey
*/
#pragma once
#include <cassert>
#include <functional>
#include <iomanip>
#include <iostream>
#include <list>
#include <string>
#include <vector>
#include <typeinfo>
namespace c9 {
template <typename Iter>
using select_access_type_for = std::conditional_t<
std::is_same_v<Iter, std::vector<bool>::iterator> ||
std::is_same_v<Iter, std::vector<bool>::const_iterator>,
typename Iter::value_type,
typename Iter::reference
>;
template <typename ... Args, std::size_t ... Index>
auto any_match_impl(std::tuple<Args...> const & lhs,
std::tuple<Args...> const & rhs,
std::index_sequence<Index...>) -> bool
{
auto result = false;
result = (... | (std::get<Index>(lhs) == std::get<Index>(rhs)));
return result;
}
template <typename ... Args>
auto any_match(std::tuple<Args...> const & lhs, std::tuple<Args...> const & rhs)
-> bool
{
return any_match_impl(lhs, rhs, std::index_sequence_for<Args...>{});
}
template <typename ... Iters>
class zip_iterator
{
public:
using value_type = std::tuple<
select_access_type_for<Iters>...
>;
zip_iterator() = delete;
zip_iterator(Iters && ... iters)
: m_iters {std::forward<Iters>(iters)...}
{
}
auto operator++() -> zip_iterator&
{
std::apply([](auto && ... args){ ((args += 1), ...); }, m_iters);
return *this;
}
auto operator++(int) -> zip_iterator
{
auto tmp = *this;
++*this;
return tmp;
}
auto operator!=(zip_iterator const & other)
{
return !(*this == other);
}
auto operator==(zip_iterator const & other)
{
auto result = false;
return any_match(m_iters, other.m_iters);
}
auto operator*() -> value_type
{
return std::apply([](auto && ... args){
return value_type(*args...);
}, m_iters);
}
private:
std::tuple<Iters...> m_iters;
};
/* std::decay needed because T is a reference, and is not a complete type */
template <typename T>
using select_iterator_for = std::conditional_t<
std::is_const_v<std::remove_reference_t<T>>,
typename std::decay_t<T>::const_iterator,
typename std::decay_t<T>::iterator>;
template <typename ... T>
class zipper
{
public:
using zip_type = zip_iterator<select_iterator_for<T> ...>;
template <typename ... Args>
zipper(Args && ... args)
: m_args{std::forward<Args>(args)...}
{
}
auto begin() -> zip_type
{
return std::apply([](auto && ... args){
return zip_type(std::begin(args)...);
}, m_args);
}
auto end() -> zip_type
{
return std::apply([](auto && ... args){
return zip_type(std::end(args)...);
}, m_args);
}
private:
std::tuple<T ...> m_args;
};
template <typename ... T>
auto zip(T && ... t)
{
return zipper<T ...>{std::forward<T>(t)...};
}
}
Example
#include "zip.hpp"
#include <vector>
std::vector<int> a, b, c;
void foo() {
for (auto && [x, y] : zip(a, b))
c.push_back(x + z);
}
Boost.Iterators has zip_iterator you can use (example's in the docs). It won't work with range for, but you can use std::for_each and a lambda.
Here is a simple version that does not require boost. It won't be particularly efficient as it creates temporary values, and it does not generalise over containers other than lists, but it has no dependencies and it solves the most common case for zipping.
template<class L, class R>
std::list< std::pair<L,R> > zip(std::list<L> left, std::list<R> right)
{
auto l = left.begin();
auto r = right.begin();
std::list< std::pair<L,R> > result;
while( l!=left.end() && r!=right.end() )
result.push_back( std::pair<L,R>( *(l++), *(r++) ) );
return result;
}
Although the other versions are more flexible, often the point of using a list operator is make a simple one-liner. This version has the benefit that the common-case is simple.

Specialize function for map like containers

I want specialize a function template for vector and map like containers. For vector I can do like below but I don't know how can I have a specialized version of the function that will be used only for map like containers.
#include <iostream>
#include <vector>
#include <map>
using namespace std;
template<typename Iterator>
void print(Iterator begin, Iterator end)
{
while (begin != end)
{
cout << *begin << endl; // compiler error for map like containers
++begin;
}
}
int main()
{
vector<int> noVec = { 1, 2, 3 };
print(noVec.begin(), noVec.end());
map<int, int> nosMap;
nosMap[0] = 1;
nosMap[1] = 2;
nosMap[3] = 3;
print(nosMap.begin(), nosMap.end());
return 0;
}
This question is similar but it suggests to use pair in vector which I don't want to do. I know the specialization can be done with SFINAE but don't know what condition to check for. It would be great if I can achieve this with C++ 11 type_traits.
The value_type of a map is some pair so you could check if the value_type of the iterator is a std::pair or not, e.g.
#include <vector>
#include <map>
#include <iostream>
template <typename>
struct is_pair : std::false_type
{ };
template <typename T, typename U>
struct is_pair<std::pair<T, U>> : std::true_type
{ };
template <typename Iter>
typename std::enable_if<is_pair<typename std::iterator_traits<Iter>::value_type>::value>::type
print(Iter begin, Iter end)
{
std::cout << "called with map-like" << std::endl;
for (; begin != end; ++begin)
{
std::cout << begin->second;
}
std::cout << std::endl;
}
template <typename Iter>
typename std::enable_if<!is_pair<typename std::iterator_traits<Iter>::value_type>::value>::type
print(Iter begin, Iter end)
{
std::cout << "called with vector-like" << std::endl;
for (; begin != end; ++begin)
{
std::cout << *begin;
}
std::cout << std::endl;
}
int main()
{
std::vector<int> vec { 1, 2, 3 };
std::map<int, int> map {{0, 0}, {1, 1}, {2, 4}, {3, 9}};
print(vec.begin(), vec.end());
print(map.begin(), map.end());
}
which prints
called with vector-like
123
called with map-like
0149
You don't need to specialize anything. All you have to do is to provide an overloaded output operator<< for std::pair, like the example below:
template<typename T1, typename T2>
std::ostream& operator<<(std::ostream &out, std::pair<T1, T2> const &mp) {
return (out << "(" << mp.first << ", " << mp.second << ")");
}
LIVE DEMO
edit:
The above solution however as #Benjamin Lindley suggested in the comments might conflict with other template overloads of the output operator<< for std::pair.
If this is the case, alternatively you could write in their own namespace (e.g., namespace detail) two template function overloads (e.g., print_elem), like the example below:
namespace detail {
template<typename T1, typename T2>
std::ostream& print_elem(std::ostream &out, std::pair<T1, T2> const &mp) {
return (out << "(" << mp.first << ", " << mp.second << ")");
}
template<typename T>
std::ostream& print_elem(std::ostream &out, T const &elem) {
return (out << elem);
}
}
and change your template print like the example below:
template<typename Iterator>
void print(Iterator begin, Iterator end)
{
while (begin != end) {
detail::print_elem(cout, *begin) << endl;
++begin;
}
}
LIVE DEMO

C++ template specialization for map-like types

I want to define a generic function for printing contents of std::map like types. My initial attempt is a function like this:
template <class K, class V>
inline void PrintCollection(const std::map<K,V>& map,
const char* separator="\n",
const char* arrow="->",
const char* optcstr="") {
typedef typename std::map<K,V>::const_iterator iter_type;
std::cout << optcstr;
for (iter_type begin = map.begin(), it = begin, end = map.end();
it != end; ++it) {
if (it != begin) {
std::cout << separator;
}
std::cout << it->first << arrow << it->second;
}
std::cout << std::endl;
}
which works fine. When I try to generalize this function one more step, i.e. make it work for std::multimap type, compiler becomes angry. I tried several ways to make std::map generic in the function definition, such as:
template <class M, class K, class V>
inline void PrintCollection(const M<K,V>& map,
const char* separator="\n",
const char* arrow="->",
const char* optcstr="") {
typedef typename M<K,V>::const_iterator iter_type;
std::cout << optcstr;
for (iter_type begin = map.begin(), it = begin, end = map.end();
it != end; ++it) {
if (it != begin) {
std::cout << separator;
}
std::cout << it->first << arrow << it->second;
}
std::cout << std::endl;
}
with no success.
How can I generalize this function as I defined above?
To be more clear, I have already a function defined for vector-like classes defined before this function. It is like
template <class T>
inline void PrintCollection(const T& collection,
const char* separator="\n",
const char* optcstr="") {
typedef typename T::const_iterator iter_type;
std::cout << optcstr;
for (iter_type begin = collection.begin(), it = begin, end = collection.end();
it != end;
++it) {
if (it != begin) {
std::cout << separator;
}
std::cout << *it;
}
std::cout << std::endl;
}
So what I want to achieve it to make this function specialized to map-like classes. I'm pretty new in C++, so I don't know the exact term for this kind of stuff. Is this called "template specialization"?
Do it like the stdlib does and use iterators in your algorithm interfaces. This is the most generic solution.
template<class Iter>
void PrintCollection(Iter first, Iter last,
const char* separator="\n",
const char* arrow="->",
const char* optcstr="")
{
typedef Iter iter_type;
std::cout << optcstr;
for (iter_type begin = first, it = begin, end = last;
it != end; ++it) {
if (it != begin) {
std::cout << separator;
}
std::cout << it->first << arrow << it->second;
}
std::cout << std::endl;
}
int main()
{
vector<pair<int, int>> collection;
map<int, int> collection2;
pair<int, int> collection3[3];
PrintCollection(begin(collection), end(collection));
PrintCollection(begin(collection2), end(collection2));
PrintCollection(begin(collection3), end(collection3));
}
The answer is fairly simple.
There is no dependency on typenames K and V in the function. So remove them and make a general template. It can be used for both map and multimap:
template <class AnyMap>
void PrintCollection(const AnyMap& map,
...
{
typedef typename AnyMap::const_iterator iter_type;
On side note, with templates, you don't need inline keyword.
You could use a template-template parameter
template<template<class, class> class M, class K, class V>
inline void PrintCollection(const M<K, V>& map, /* rest as before */)
{
// rest as before
}
int main()
{
std::map<int, int> m1;
std::multi_map<int, int> m2;
// fill both maps
PrintCollection(m1);
PrintCollection(m2);
}
But as hansmaad is pointing out, you could also use a pair of iterators instead of the container as parameter. In general, you would prefer that solution if your PrintCollection is very generic and does not make use of the fact that it has a Key and Value type. OTOH, if your PrintCollection also needs to print that information in some future version, then you might want to use a template-template parameter that takes those two types as parameters.