如何声明一对对的任意深度



一对int可以声明为:std::pair<int, std::pair<int, int> > A;类似地,一对int作为std::pair<int, std::pair<int, std::pair<int, int> > >A;我想宣布一个任意的";成对的";在我的代码中。即,根据某个值(仅在运行时已知(,我想要一对int(n = 1(或一对int对(n = 2(等等。我想知道如何在C++中有效地做到这一点吗?

以下是Python中的一段代码:

import numpy as np
n = 4 # a value known at runtime
m = 2 # a value known at runtime
def PP(A, j):
A_s = []
if j == n-1:
for i in range(1, m):
A_s.append((i, A[i]))
else:
for i in range(1, m):
A_c = A[i]
A_s.append((i, PP(A_c, j+1)))
return A_s
j = 0
# The dimension of A is known at runtime.
# Will have to create np.ones((m, m, m, m, m)) if n = 5
A = np.ones((m, m, m, m))
B = PP(A, 0)

与Python不同,C++是一种静态类型的语言。因此,如果要存储的内容的结构或大小直到运行时才知道,则不能像嵌套对一样使用类型本身来描述特定的结构。相反,您所做的是使用可以动态调整大小的C++类型。也就是说,std::vector<int>是在C++中存储动态整数的惯用且有效的方法。

如果您真的想要像Python示例([(1, [(1, [(1, [(1, 1.0)])])])](中那样的树状结构,那么这在C++中也是可能的。但这需要更多的工作。例如参见C++中的二进制树:第1部分。

C++(参见本网站和n3337,C++11标准草案(同时具有std::variantstd::optional(在C++17中(。似乎您想要一些标记的并集(如C++编译器中的抽象语法树(和智能指针(例如std::unique_ptr(。

也许你想要类似的东西

class Foo; // forward declaration
class Foo {
std::variant<std::unique_ptr<Foo>, std::pair<int,int>> fields;
/// many other things, in particular for the C++ rule of five
};

与Python相反,每个C++值都有一个已知的类型

您可以巧妙地将两者结合起来,并且可能对其他标准容器(特别是std::vector(感兴趣。请阅读一本好的C++编程书籍,并注意五条规则。

从github或gitlab上的现有开源软件(如Qt、RefPerSys、Wt、Fish、Clang静态分析仪、GCC和许多其他(中获得灵感

还请阅读C++编译器(如GCC(和调试器(如GDB(的文档。如果您使用最近的GCC,请使用所有警告和调试信息进行编译,例如g++ -Wall -Wextra -g。通过编写编码约定进行文档记录,对于足够大的代码库,可以考虑编写GCC插件来强制执行它们。最近的GCC(2020年10月的GCC 10(有一些有趣的静态分析选项,你可以试试。

考虑在C++代码库中使用Clang静态分析器(另请参阅本报告草案、DECODER和CHARIOT欧洲项目以及MILEPOST GCC(。

也可以阅读最近ACM SIGPLAN会议上关于C++的论文。

您也可以定义class Matrix,或者使用提供它们的现有库(例如boost(,也许可以将这个答案调整为C++。

请记住,每个C++类型的sizeof在编译时都是已知的。AFAIK、C++没有任何灵活的数组成员(就像C一样(。

正如其他人已经说过的,你不能这样做。至少在运行时不会。

然而,总的来说,它似乎也没有用处。假设您有以下类型(与您的类型类似,但在编译时具有已知的嵌套级别(,并声明该类型的对象

using your_type = std::pair<int, std::pair<int, std::pair<int, int>>>
your_type obj1{1,{2,{3,4}}};

这与没有什么不同

std::array<int,4> obj2{1,2,3,4};

你的信件在哪里:

  • obj1.first == obj2[0]
  • obj1.second.first == obj2[1]
  • obj1.second.second.first == obj2[2]
  • obj1.second.second.second == obj2[3]

为了强调它们实际上是一样的,请考虑如何为这样的类型实现size函数;它可能是这样的元函数(可能有更好的方法(:

template<typename T, typename Ts>
constexpr int size(std::pair<T,Ts>) {
if constexpr (std::is_same_v<T,Ts>)
return 2;
else
return 1 + size(Ts{});
}

换句话说,它们是同构的

现在,您的要求是以这样一种方式编写your_type,即在运行时已知嵌套级别。如前所述,这是不可能的,但猜猜与你想象的类型同构是什么?std::vector<int>

所以我的答案是:你不需要;只需使用std::vector即可

最后,根据我的回答,如果真的想要一个行为像任意嵌套对的类型,那么你可以在std::vector周围写一个包装器,这似乎是合理的。但我不明白为什么你真的需要这么做。

最新更新