【问题标题】:Should third-party types be exposed in my C++ library's API第三方类型是否应该在我的 C++ 库的 API 中公开
【发布时间】:2012-05-21 12:53:33
【问题描述】:

我正在开发一个 C++ 库,用户将在其中提供复杂的输入,例如 矩阵和四元数。我不想重新实现这些类型,所以, 在内部,我将使用Eigen 库。

我正在尝试确定将这些类型公开给我的库的最佳方式' 客户,并为我的 API 提供了一些选项。我使用四元数 以 type 为例,但这同样适用于矩阵等。还, 虽然我是在专门谈论暴露 Eigen 的类型,但我猜这个 问题同样适用于正在使用的其他外部库。

1) 仅使用基本 C++ 类型

此选项将要求客户端通过基本类型传入数据。为了 例如,要传入一个四元数(4 个元素),可以这样做:

void my_func(double my_quat[4])

2) 公开 Eigen 的类型

Eigen 为数组和四元数提供了几种模板类型。为了 例如,如果一个函数需要一个四元数,我可以使用 Eigen 的 Quaterniond 类型(实际上是 Quaternion<double> 的 typedef):

void my_func(const Eigen::Quaterniond& my_quat)

3) 为客户端的各种类型创建一个简单的包装器

我可以创建一个非常简单的四元数类型(例如,某种简单的结构) 客户必须创建(也许通过某种工厂功能)来 传递给我的 API:

void my_func(const quaternion_t& my_quat)

我的库会将quaternion_t 类型转换为我的内部特征 表示。

我不太喜欢选项 1,因为我希望有更强烈的感觉 输入我的 API。选项 2 将要求我的客户也使用 Eigen,而不是 提到兼容性的潜在问题,如果他们使用不同的 Eigen 的版本(顺便说一下,Eigen 是一个仅标头库,如果 事项)。剩下的选项 3。

人们怎么看?我基本上回答了我自己的问题吗?有什么例子吗?

相关问题

here 提出了一个相关问题,但并未真正详细说明是否应该 公开外部类型。

【问题讨论】:

  • 选项 3 怎么样,构造函数同时采用选项 1 和 2? C++ 语义允许您很好地转发声明类型以使其工作(没有 Eigen 的客户端仍然可以包含标头并且不会在编译时失败)。
  • 我正在考虑类似的事情,但我想我对如何转发声明 typedef'd 模板类型有点模糊,尽管我想在我的情况下我可能会限制客户通过类型的特定实例化(例如 Quaternion<double> 而不是 Quaternion<int>)。
  • 如果客户使用构造函数将我的库的类型从他们的 Eigen 类型中创建出来,我也有点模糊,但是他们使用的是不同版本的 Eigen,比如说,有轻微的实施变化。

标签: c++ api


【解决方案1】:

公开 3rd 方库在短期内是最容易的,但从长远来看,最有可能在背后咬你一口。最简单,因为类型已经存在,你不需要自己想出。如果您将来想要使用不同的实现库,或者想要允许扩展客户端传递给您的数据,那么您会受到影响。

只使用基本类型几乎就像想出你自己的一样,但它的级别要低得多,没有充分的理由。如果不经常参考关于什么是什么的文档,您的用户将很难使用您的库。

如果您希望获得灵活性,那么使用您自己的类型是最好的选择。由于您需要重新创建所有已经存在的类型,这似乎需要大量的工作,但是如果您给它一些努力,您可能会发现如果您在库的接口中使用稍微不同的类型,它将有助于实现以后改得更好。

因此,答案实际上取决于您的目标和长期计划/预测:如果您认为自己不会从当前的实施中改变,您可以重新使用现有类型,但如果您预见/计划未来变化,你应该创建自己的独立界面。

【讨论】:

    【解决方案2】:

    包装/封装。假设您想添加一些附加功能,例如缓存计算结果,例如四元数的范数,作为实现更改。如果您在不强制您的客户端代码更改其调用的情况下公开第 3 方类型,则无法做到这一点(很容易)。

    【讨论】:

    • 我同意。但是,我不一定要公开整个矩阵/四元数/等。我自己的图书馆,因为我的图书馆的功能将处于更高的水平。让我的包装类提供最少量的功能来与我的 API 通信,并让客户使用他们想要的任何东西来实际操作与这些类型关联的数据是否有意义?
    • 薄包装是可以的。 my_quaternion::foo() { return their_quaternion.foo(); } 对于您要公开的功能很好。正如@Attila 在上面指出的那样,最引人注目的情况是您想要切换库,您的客户不应该处理这样的麻烦。如果您觉得客户需要从 eigen 对成熟的数学对象进行大量访问:还提供一个转换函数 getEigen() 和一个以 eigen 作为输入的 ctor,您将保证即使在您在另一个库中重新实现。
    • 如果使用 ctor 或 getEigen() 函数的客户端和我的库使用不同版本的 Eigen 编译会发生什么?我假设如果两个版本都兼容 ABI,那么我们很好。但是,如果某些事情发生了变化,这会不再起作用吗?特别是,我正在考虑将我的库作为 DSO 提供的情况,但我想我不知道如果我给客户一个静态库会发生什么。
    • 这个问题在我脑海中浮现,但最好将它作为一个单独的问题发布。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-04-06
    • 1970-01-01
    • 1970-01-01
    • 2023-03-13
    • 1970-01-01
    • 1970-01-01
    • 2017-11-02
    相关资源
    最近更新 更多