C++ 在API中处理复杂的嵌套类型

C++ 在API中处理复杂的嵌套类型,c++,types,architecture,api-design,naming,C++,Types,Architecture,Api Design,Naming,让我们假设有一个与图像处理相关的项目。我们有一个算法可以计算两幅图像之间的“分数”(无论是什么),因此: double score(Image i1, Image i2) 如果我们有多个帧(图像),我们希望计算所有帧(将所有帧与所有帧匹配): std::vector score(std::vector image);//[1] (整数对表示图像向量中的图像索引,因为我们将“全部”与“全部”匹配) 不幸的是,我们从许多设备获取图像,其中每个设备都可以有多个流(然后是每个流中的多个连续帧),这使

让我们假设有一个与图像处理相关的项目。我们有一个算法可以计算两幅图像之间的“分数”(无论是什么),因此:

double score(Image i1, Image i2)
如果我们有多个帧(图像),我们希望计算所有帧(将所有帧与所有帧匹配):

std::vector score(std::vector image);//[1]
(整数对表示图像向量中的图像索引,因为我们将“全部”与“全部”匹配)

不幸的是,我们从许多设备获取图像,其中每个设备都可以有多个流(然后是每个流中的多个连续帧),这使得图像复杂到了这个程度:

std::vector<std::vector<std::vector<std::pair<std::pair<int, int>, double>>>>
     ^devices    ^streams    ^frames     ^score   ^image indices
std::vector ^设备^streams^帧^score^图像索引 如何处理必须返回如此复杂类型的函数


这只是关于用typedefs包装它并正确命名?或者,您可能只允许用户使用更简单的API版本,即使用一个向量[1],然后自己进一步包装它?或者,对于这种情况,可能有什么奇特的模式吗?

在不太了解数据的情况下,一种选择是创建结构或类来包装各个部分:

namespace your_company {
struct index {
    std::pair<int, int> indexes;
};
struct frame {
    std::pair<index, double> scores;
};
struct stream {
    std::vector<frame> frames;
};
struct device {
    std::vector<stream> streams;
};
}

一般来说,你通过给事物取专有名称来处理复杂性

当我在
[1]
中看到您的API时,我看到了一个图形,其中图像是图形的节点,您将边作为邻接列表返回。邻接信息也可以以对称邻接矩阵的形式存储。为您的问题使用合适的术语,可能会使您能够访问大量工具,例如Boost.Graph之类的库。这可能是您编写自己的可重用组件的起点。你甚至可能会发现人们在处理你正试图解决的问题,只是用更抽象的术语

这只是一种选择,当你考虑正确命名事物时,美妙的事情就会发生

关于复杂性的第二次跳跃,我认为可能是调用方决定他们想要输入到算法中的块的大小,因为这似乎人为地限制了函数的用例。如果你认为,情况并非如此,你仍然应该给这些东西取个适当的名字。您可以使用结构和类,这一选择可能非常糟糕:

using AdjacencyList = std::vector<std::pair<std::pair<int, int>, double>;
// Info that might also be represented as a matrix or symmetric matrix.

class SimilarityData
{
    public:
        const AdjacencyList &
        getAdjacencyList(
            int device,
            int stream,
            int frame ) const;
};

使用AdjacencyList=std::vector您是否错过了
[1]
中的第二个
std::pair
?Typedefs(即
使用X=Y;
)应该是保持其可读性的第一步。但只有当设计本身是合理的,这是很难判断的(难道你不想把每个级别的集合封装在某种类中,提供其他有用的东西吗?)…如果是API,我真的看不出
device/stream/frames
参数的原因
score()
不应该关心它们。对于
score(std::vector images)
,我个人会返回一个2D数组(自定义类或
vector
)是的,谢谢@evgindect,它可以比许多嵌套类型更干净,但我担心仅仅为了这个目的引入很多新结构。我同意,这似乎限制了函数的使用情况。我会考虑要么只提供较不复杂的函数(例如只使用一对),或者可能两者都过载。太好了!只需考虑更复杂的重载可能属于调用代码,该调用代码以特定的方式使用您的函数。考虑到您在该级别上有很多额外的上下文,因此应该更容易理解其中的专有名称。如果确实有多个独立的调用者以一种特定的方式使用您的函数,那么使用专有名称也应该变得容易得多。
struct device {
    std::vector<stream> streams;
    std::string name;
};
your_company::device d = your_function();
d.streams[0].frames[0].scores[0].pair[0].....
using AdjacencyList = std::vector<std::pair<std::pair<int, int>, double>;
// Info that might also be represented as a matrix or symmetric matrix.

class SimilarityData
{
    public:
        const AdjacencyList &
        getAdjacencyList(
            int device,
            int stream,
            int frame ) const;
};