Sequence-zip function for C++11?
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.
Python's zip() equivalent in C or C++
int **zip(int *arr1, int *arr2, int length)
{
int **ret = new int*[length];
for(int i = 0; i<length; i++)
{
ret[i] = new int[2];
ret[i][0] = arr1[i];
ret[i][1] = arr2[i];
}
return ret;
}
Understanding zip function in Python and adapting it for C
Your code creates the eight vertices of an axis-aligned cube in a specific order. In C, a more or less faithful rendering of the Python code could look like this:
struct point {
double x, y, z;
};
double s = 1.0;
const double zz[2] = {-s / 2, s / 2};
const double xx[4] = {-s / 2, s / 2, s / 2, -s / 2}; // zipped list, left
const double yy[4] = {s / 2, s / 2, -s / 2, -s / 2}; // zipped list, right
struct point p[8];
unsigned n = 0;
for (unsigned i = 0; i < 2; i++) {
for (unsigned j = 0; j < 4; j++) {
p[n].x = xx[j];
p[n].y = yy[j];
p[n].z = zz[i];
n++;
}
}
C doesn't have generators, so his code just fills an array. Zip might look like a good way to achieve this in Python, but Python isn't C, so don't bother to write your own zip. A more typical rendering of your code in C might look like this:
struct point p[8] = {
{-s / 2, s / 2, -s / 2},
{ s / 2, s / 2, -s / 2},
{ s / 2, -s / 2, -s / 2},
{-s / 2, -s / 2, -s / 2},
{-s / 2, s / 2, s / 2},
{ s / 2, s / 2, s / 2},
{ s / 2, -s / 2, s / 2},
{-s / 2, -s / 2, s / 2}
};
Implementing meta-function zip in c++11
This is the shortest implementation I've discovered:
template <typename...> struct typelist { };
template <typename A,typename B> struct prepend;
template <typename A,typename B> struct joincols;
template <typename...> struct zip;
template <typename A,typename... B>
struct prepend<A,typelist<B...> > {
typedef typelist<A,B...> type;
};
template <>
struct joincols<typelist<>,typelist<> > {
typedef typelist<> type;
};
template <typename A,typename... B>
struct joincols<typelist<A,B...>,typelist<> > {
typedef typename
prepend<
typelist<A>,
typename joincols<typelist<B...>,typelist<> >::type
>::type type;
};
template <typename A,typename... B,typename C,typename... D>
struct joincols<typelist<A,B...>,typelist<C,D...> > {
typedef typename
prepend<
typename prepend<A,C>::type,
typename joincols<typelist<B...>,typelist<D...> >::type
>::type type;
};
template <>
struct zip<> {
typedef typelist<> type;
};
template <typename A,typename... B>
struct zip<A,B...> {
typedef typename joincols<A,typename zip<B...>::type>::type type;
};
Printing compile-time integer sequence in C++11
Isn't clear to me what exactly do you want obtain and the meaning of what you have done (why Facility
? why List
inside facility?).
I just give you an example of how to write Print()
without recursion, using an unused array (and defining IntList
, as suggested by Yakk, taking inspiration from std::integer_sequence
)
#include <iostream>
#include <functional>
template <typename T, T ... Nums>
struct IntList
{
static void Print (std::ostream & s = std::cout)
{
using unused = int[];
(void)unused { 0, ((void)(s << Nums << ", "), 0)... };
s << std::endl;
}
};
int main()
{
using List1 = IntList<int, 1, 2, 3>;
List1::Print();
}
If you can use C++17 instead of C++11/C++14, you can write Print()
without the unused hack, simply unpacking Nums
as follows
static void Print (std::ostream & s = std::cout)
{ (s << ... << (s << Nums, ", ")) << std::endl; }
Regarding concat and sort, I suppose you want member function that return (by example, the concat) a IntList
with a concatenation of the two lists of numbers.
The a simple concat example can be the following static member for IntList
template <T ... Nums2>
static constexpr IntList<T, Nums..., Nums2...>
Concat (IntList<T, Nums2...> const &)
{ return {}; }
So you can write something like
constexpr IntList<int, 1, 2, 3> l1;
constexpr IntList<int, 4, 5, 6> l2;
constexpr auto l3 = l1.Concat(l2);
l3.Print(); // print 1, 2, 3, 4, 5, 6,
I leave you the sort function as simple exercise :-)
boost zip_iterator and std::sort
You can't sort a pair of zip_iterators.
Firstly, make_zip_iterator takes a tuple of iterators as input, so you could call:
boost::make_zip_iterator(boost::make_tuple( ... ))
but that won't compile either, because keys
and keys+N
doesn't have the same type. We need to force keys
to become a pointer:
std::sort(boost::make_zip_iterator(boost::make_tuple(+keys, +values)),
boost::make_zip_iterator(boost::make_tuple(keys+N, values+N)));
this will compile, but the sorted result is still wrong, because a zip_iterator only models a Readable iterator, but std::sort
also needs the input to be Writable as described here, so you can't sort using zip_iterator.
How can I iterate over two vectors simultaneously using BOOST_FOREACH?
Iterating over two things simultaneously is called a "zip" (from functional programming), and Boost has a zip iterator:
The zip iterator provides the ability to parallel-iterate over several
controlled sequences simultaneously. A zip iterator is constructed
from a tuple of iterators. Moving the zip iterator moves all the
iterators in parallel. Dereferencing the zip iterator returns a tuple
that contains the results of dereferencing the individual iterators.
Note that it's an iterator, not a range, so to use BOOST_FOREACH
you're going to have to stuff two of them into an iterator_range or pair
. So it won't be pretty, but with a bit of care you can probably come up with a simple zip_range
and write:
BOOST_FOREACH(boost::tuple<int,int> &p, zip_range(v1, v2)) {
doSomething(p.get<0>(), p.get<1>());
}
Or special-case for 2 and use std::pair
rather than boost::tuple
.
I suppose that since doSomething
might have parameters (int&, int&)
, actually we want a tuple<int&,int&>
. Hope it works.
Related Topics
Does Initialization Entail Lvalue-To-Rvalue Conversion? Is 'Int X = X;' Ub
What Are Transparent Comparators
Which Is Faster: Stack Allocation or Heap Allocation
How to Use a Binary Literal in C or C++
How to Pass a Member Function Where a Free Function Is Expected
Static Linking VS Dynamic Linking
Why Do C and C++ Compilers Allow Array Lengths in Function Signatures When They'Re Never Enforced
Which Is the Fastest Algorithm to Find Prime Numbers
Why How to Not Push_Back a Unique_Ptr into a Vector
Setup Opencv-2.3 For Visual Studio 2010
How to Link to a Library With Code::Blocks
Function Parameter Evaluation Order
Optimizing Away a "While(1);" in C++0X
Concatenating Two Std::Vectors
"Undefined Reference To" Template Class Constructor