[英]How to print a n-dimensional c++ STL container? Container is array of arrays or vectors of vectors
[英]how to print an n-dimensional array in c++
我想写一个 function 可以打印不同的 arrays。 例如:
#include<iostream>
using namespace std;
int main(){
int a[10];
int b[3][2];
for(int i = 0; i < 10; i++){
a[i] = i;
}
for(int i = 0; i < 3; i++){
for(int j = 0; j < 2; j++){
b[i][j] = i * 2 + j;
}
}
print_arr(a, /*some input*/);
// output: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
print_arr(b, /*some input*/);
// output:
// 0, 1
// 2, 3
// 4, 5
return 0;
}
有人可以帮助我还是说这是不可能的。 也许这个问题已经回答了。 在这种情况下,请您分享该问题的链接
您可以创建一个 function 模板以递归方式展开数组。
例子:
#include <iostream>
#include <type_traits>
// only enable the function for arrays
template<class T, std::enable_if_t<std::is_array_v<T>, int> = 0>
void print_arr(const T& x) {
for(auto& in : x) {
if constexpr (std::rank_v<T> > 1) // more dimensions to go
print_arr(in); // call to unwrap next dimension
else
std::cout << in << ' '; // last dimension, print the value
}
std::cout << '\n';
}
由于名称print_arr
表明您不需要SFINAE ,您还可以用 function 中的static_assert
替换模板的enable_if_t
部分:
template<class T>
void print_arr(const T& x) {
static_assert(std::is_array_v<T>);
// ...
除了直接流式传输到std::cout
,您可以添加一个std::ostream&
参数以使其 stream 到任何stream
template<class T>
void print_arr(std::ostream& os, const T& x) {
static_assert(std::is_array_v<T>);
for(auto& in : x) {
if constexpr (std::rank_v<T> > 1)
print_arr(os, in);
else
os << in << ' ';
}
os << '\n';
}
// ...
print_arr(std::cout, a);
print_arr(std::cout, b);
或者你可以让它返回一个完整的 output 的std::string
,这让你以后可以用它做你想做的事。
例子:
#include <sstream>
template<class T>
std::string print_arr(const T& x) {
static_assert(std::is_array_v<T>);
std::ostringstream os;
for(auto& in : x) {
if constexpr (std::rank_v<T> > 1)
os << print_arr(in);
else
os << in << ' ';
}
os << '\n';
return os.str();
}
// ...
std::cout << print_arr(a);
std::cout << print_arr(b);
Ted Lyngmo 的回答绝对是最简洁的,并且可能最接近实现您的要求,但仍有一些事情值得指出,包括在某些情况下可能有意义的替代解决方案。
首先,阅读本文的任何人都必须了解 C 和 C++ 类型默认不包含任何类型的运行时类型信息。 是的,这是真的,记录类型存在 RTTI,但是像int arr[2][3]
这样的内置 C 数组只不过是一点糖说“给我一个 memory 的区域,足以存储 6 个整数”。 例如,这与 python 之类的语言形成对比,其中列表 object 将包含有关大小和内容的元数据。 正是这种元数据允许您编写非常灵活的函数,而不是查询 object 本身的结构,当然这是有代价的。
当我们引入像上面这样的模板化解决方案时,我们没有添加运行时类型信息,我们已经要求编译器为我们可能需要的每个可能的数组类型排列生成代码。 如果你只有几个,这很好,但如果 function 被大量使用,有许多不同的数组类型,事情就会增长得非常快。 在某些环境中,这实际上可能成为问题。 例如,考虑以下主要 function:
int main(int argc, char **argv)
{
int arr1[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
print_arr(arr1);
int arr2[3] = {13, 14, 15};
print_arr(arr2);
int arr3[3][2][2] = {{{10, 20}, {30, 40}}, {{50, 60}, {70, 80}}, {{90, 100}, {110, 120}}};
print_arr(arr3);
return 0;
}
现在看看生成的 AST:
jon@prompt$ clang++ -fsyntax-only -Xclang -ast-dump test.cpp -std=c++17 | grep FunctionDecl | grep print_arr
| |-FunctionDecl 0x10921fd88 <line:6:1, line:15:1> line:6:6 print_arr 'void (const T &)'
| |-FunctionDecl 0x109224c18 <line:6:1, line:15:1> line:6:6 used print_arr 'void (int const &[3][4])'
| |-FunctionDecl 0x109225ab8 <line:6:1, line:15:1> line:6:6 used print_arr 'void (int const &[3])'
| |-FunctionDecl 0x1092270a8 <line:6:1, line:15:1> line:6:6 used print_arr 'void (int const &[3][2][2])'
| |-FunctionDecl 0x10933db08 <line:6:1, line:15:1> line:6:6 used print_arr 'void (int const &[4])'
| |-FunctionDecl 0x1093539a8 <line:6:1, line:15:1> line:6:6 used print_arr 'void (int const &[2][2])'
| `-FunctionDecl 0x1093552d8 <line:6:1, line:15:1> line:6:6 used print_arr 'void (int const &[2])'
在这里,您会看到编译器针对我们使用的每个数组大小排列发出了不同版本的print_arr
function。 这并不是你可以合理地称之为“一个函数”的东西,它实际上是许多函数,每个函数都是由编译器自动生成的。 在 cpp 文件中写入的文本量很小,但生成的实际代码量非常可观。
解决此问题的另一种方法是在print_arr
function 中包含类型信息。 这是一个所见即所得的实现示例,尽管您需要手动提供类型元数据,但您可以执行相同的操作:
const int *print_arr(const int *arr, const int rank, const int *lengths)
{
const char *p_sep = "";
printf("{");
if (rank > 1) {
for (int i = 0; i < lengths[0]; i++) {
printf("%s", p_sep);
arr = print_arr(arr, rank - 1, &lengths[1]);
p_sep = ", ";
}
} else {
for (int i = 0; i < lengths[0]; i++) {
printf("%s%d", p_sep, *arr++);
p_sep = ", ";
}
}
printf("}");
return arr;
}
以下是您将如何将它与相同的示例 arrays 一起使用:
int main(int argc, char **argv)
{
int arr1[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
print_arr(&arr1[0][0], 2, (int[2]){3, 4});
printf("\n");
int arr2[3] = {13, 14, 15};
print_arr(&arr2[0], 1, (int[1]){3});
printf("\n");
int arr3[3][2][2] = {{{10, 20}, {30, 40}}, {{50, 60}, {70, 80}}, {{90, 100}, {110, 120}}};
print_arr(&arr3[0][0][0], 3, (int[3]){3, 2, 2});
printf("\n");
return 0;
}
Output:
jon@promptC$ ./test
{{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}}
{13, 14, 15}
{{{10, 20}, {30, 40}}, {{50, 60}, {70, 80}}, {{90, 100}, {110, 120}}}
这种方法有几个优点,最重要的是编译器几乎完全准确地发出了所写的内容。 它还迫使您在代码中非常明确,这在这种情况下可能很好。
与 C 和 C++ 一样,您需要知道最适合您所处的情况。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.