如何打印任意数量或随机访问的容器?
How to print any number or random access containers?
假设我有 N 个不同类型的随机访问容器(例如 std::vector
和 std::array
),并且所有容器的长度都相同。我想写一个以列顺序打印它们的函数,即:
#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";
}
现在假设所有容器都包含标准数字类型,我可以编写一个可变参数模板函数,如下所示:
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
}
我使用 std::complex<long double>
的地方,因为它会包含任何可能的数字。
然而,这个解决方案并不令人满意,因为我分配了额外的内存,我正在转换一些整数,破坏了输出(可能还有精度),最后,如果任何容器包含不能平凡转换为的可打印类型,该解决方案就不起作用一个数字类型。
关于如何编写更通用的解决方案有什么想法吗?
您不需要创建任何临时文件。这是一个要求至少存在一个容器的实现,但您可以通过添加空重载来删除该要求:
// 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';
}
}
这利用 C++17 fold expressions 在手动打印第一个元素后打印每个容器的第 i 个元素。显式处理第一个还可以确保我们不会在没有分支的每一行的末尾(或开头)打印额外的 space。
如果您无法访问 C++17,它仍然可以实现,但会比这丑陋得多。
根据 Louis 的评论,您还可以在 for 循环之前添加一个 assert
以确保所有容器中至少包含 front.size()
个元素以确保安全:
assert(((cs.size() >= front.size()) && ...));
将 >=
更改为 ==
以实现严格相等。
用法:
int main() {
std::array<int, 4> a{1,2,3,4};
std::vector<int> b{5,6,7,8};
vprint(a, b);
}
版画
1 5
2 6
3 7
4 8
假设我有 N 个不同类型的随机访问容器(例如 std::vector
和 std::array
),并且所有容器的长度都相同。我想写一个以列顺序打印它们的函数,即:
#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";
}
现在假设所有容器都包含标准数字类型,我可以编写一个可变参数模板函数,如下所示:
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
}
我使用 std::complex<long double>
的地方,因为它会包含任何可能的数字。
然而,这个解决方案并不令人满意,因为我分配了额外的内存,我正在转换一些整数,破坏了输出(可能还有精度),最后,如果任何容器包含不能平凡转换为的可打印类型,该解决方案就不起作用一个数字类型。
关于如何编写更通用的解决方案有什么想法吗?
您不需要创建任何临时文件。这是一个要求至少存在一个容器的实现,但您可以通过添加空重载来删除该要求:
// 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';
}
}
这利用 C++17 fold expressions 在手动打印第一个元素后打印每个容器的第 i 个元素。显式处理第一个还可以确保我们不会在没有分支的每一行的末尾(或开头)打印额外的 space。
如果您无法访问 C++17,它仍然可以实现,但会比这丑陋得多。
根据 Louis 的评论,您还可以在 for 循环之前添加一个 assert
以确保所有容器中至少包含 front.size()
个元素以确保安全:
assert(((cs.size() >= front.size()) && ...));
将 >=
更改为 ==
以实现严格相等。
用法:
int main() {
std::array<int, 4> a{1,2,3,4};
std::vector<int> b{5,6,7,8};
vprint(a, b);
}
版画
1 5
2 6
3 7
4 8