Let's assume I have N random access containers (std::vector
and std::array
for example) of different types, and that all containers have the same length. I want to write to write a function that prints them in a column-ordered fashion, i.e.:
#include <vector>
#include <iostream>
#include <array>
#include <complex>
constexpr int nr=100;
void print(const std::vector<double>& d1, const std::array<std::complex<double>,nr>& b1, const std::vector<int>& b2, const std::array<double,nr>& d2)
{
for(int i=0; i<nr; i)
std::cout<<b1[i]<<" "<<d1[i]<<" "<<b2[i]<<" "<<d2[i]<<"\n";
}
Now assuming that all the containers contain the standard numeric types I could write a variadic template function that would look like this:
template<typename... T>
void vprint(T... cs)
{
constexpr int nc=sizeof...(T);
std::vector<std::vector<std::complex<long double>>> v(nr, std::vector<std::complex<long double>>(nc));
//then fill v recursively with all the cs and print it
}
where I used std::complex<long double>
since it would contain any possible number.
However this solution is unsatisfactory since I am allocating extra memory, I am converting some integers spoiling the output (and possibly precision), and, finally, the solution does not work if any of the containers contains a printable type that does not convert trivially to a numeric type.
Any idea on how to write a more general solution?
CodePudding user response:
You don't need to create any temporaries. Here's an implementation that requires at least one container to be present, but you can remove that requirement by adding an empty overload:
// Handles empty parameters by doing nothing
void vprint() {}
// Handle non-empty parameters
template<typename T, typename... Ts>
void vprint(const T& front, const Ts&... cs) {
for (int i = 0; i < front.size(); i) {
std::cout << front[i];
((std::cout << ' ' << cs[i]), ...);
std::cout << '\n';
}
}
This makes use of C 17 fold expressions to print the ith element of each container, after printing the first one manually. Handling the first one explicitly also ensures we don't print an extra space at the end (or beginning) of each line without branches.
If you don't have access to C 17, it can still be implemented but it'll be a lot uglier than this.
As per Louis' comment, you could also add an assert
before the for loop to make sure all the containers have at least front.size()
elements in them for safety:
assert(((cs.size() >= front.size()) && ...));
Change the >=
to ==
for strict equality.
Usage:
int main() {
std::array<int, 4> a{1,2,3,4};
std::vector<int> b{5,6,7,8};
vprint(a, b);
}
Prints
1 5
2 6
3 7
4 8