C++ 互操作性的支持特性和约束

Swift 支持与 C++ 的双向互操作性。本页介绍当前支持哪些 C++ 互操作性特性。它还讨论了当前 C++ 互操作性支持的局限性。此外,它还列出了与 C++ 互操作性支持相关的一系列约束。

C++ 互操作性是 Swift 的一项积极发展的功能。随着 Swift 社区收集关于在混合 Swift 和 C++ 代码库中实际采用 C++ 互操作性的反馈,其设计和功能的某些方面可能会在 Swift 的未来版本中发生变化。每当 Swift 的新版本更改 C++ 互操作性支持的特性集时,此页面都将进行更新。

平台支持

C++ 互操作性在 Swift 支持的所有平台上均支持开发和部署。

混合语言应用程序的最低部署版本

C++ 互操作性不会对您的应用程序施加额外的部署版本要求,除非您的 Swift 代码使用成为引用类型的 C++ 类或结构体。不使用此类引用类型的应用程序的最低部署版本与 Swift 常规的最低部署版本相同。

从 C++ 导入的引用类型的最低部署版本

下表显示了可以使用成为引用类型的 C++ 类或结构体的混合 Swift 和 C++ 应用程序可以部署的最低操作系统版本。下表中未列出的任何部署平台均自动支持,因此导入的引用类型不会对 Ubuntu 或 CentOS 等平台施加额外的部署版本要求。

运行 Swift 应用程序的平台 最低部署版本
macOS 13.3
iOS 16.4
watchOS 9.4
tvOS 16.4

编译器支持

Swift 5.9 及更高版本支持 C++ 互操作性。

Swift 对双向互操作性的支持依赖于 Swift 编译器生成的头文件,然后希望使用 Swift API 的 C++ 代码可以包含该头文件。此头文件使用仅以下 C++ 编译器支持的 Swift 特定编译器扩展

使用其他编译器构建的 C++ 代码无法从 C++ 调用 Swift 函数或使用 Swift 类型。

C++ 标准库支持

Swift 编译器在与 C++ 互操作时使用平台的默认 C++ 标准库。下表显示了为特定部署平台构建 Swift 代码时使用的 C++ 标准库

运行 Swift 应用程序的平台 默认 C++ 标准库
Apple 平台 libc++
Ubuntu、CentOS、Amazon Linux libstdc++
Windows Microsoft C++ 标准库 (msvcprt)

Swift 目前不支持为支持备用标准库的平台选择备用标准库。例如,即使 libc++ 可用于为 Ubuntu 构建 C++ 代码,您也不能在为 Ubuntu 构建 Swift 代码时使用 libc++。

混合 Swift 和 C++ 代码必须使用相同的 C++ 标准库。

使用 C++ 互操作性需要编译器启用对 C++14 标准或更高版本的支持。Swift 允许您更改它使用的 C++ 标准版本;但是,从 Swift 使用的 C++ 库头文件也必须符合所选的 C++ 标准。当使用双向互操作性时,程序需要使用 C++14 支持进行编译,因为为 Swift 模块生成的 C++ 接口使用 C++14 功能。

自定义 C++ 标准版本

以下是如何设置 Swift 编译器用于互操作性的 C++ 标准版本

支持的 C++ API

本节介绍 Swift 中支持哪些 C++ API。

Swift 中支持的 C++ 函数

Swift 支持调用大多数非模板化的

Swift 尚不支持使用右值引用类型的函数和构造函数。

Swift 支持调用某些 C++ 函数模板。任何在其签名中使用依赖类型或通用引用 (T &&) 的函数或函数模板在 Swift 中都不可用。任何带有非类型模板参数的函数模板在 Swift 中都不可用。可变参数函数模板在 Swift 中不可用。

返回类型在 Swift 中不受支持或参数类型在 Swift 中不受支持的 C++ 函数在 Swift 中不可用。

如果 C++ 函数的参数具有默认值,则如果满足以下条件,该参数在 Swift 中也将具有默认值

Swift 中支持的 C++ 类型

以下 C++ 类型可以在 Swift 中使用

在 Swift 中成为值类型的 C++ 类型可以被构造并通过值传递。

在 Swift 中成为引用类型的 C++ 类型不能直接由 Swift 代码构造。它们可以在 Swift 和 C++ 之间自由传递。

在 C++ 命名空间内定义的 C++ 类型在 Swift 中可用。

类和结构体模板在 Swift 中不可直接使用。类或结构体模板的实例化特化在 Swift 中可用。Swift 代码可以通过使用在 C++ 头文件中定义的类型别名来访问模板特化类型。

当 C++ 结构体或类的公共数据成员的类型在 Swift 中受支持时,该数据成员在 Swift 中可用。

Swift 中支持的 C++ 标准库类型

以下 C++ 标准库类型在 Swift 中受支持

其他标准库类型,例如 std::unique_ptrstd::functionstd::variant 在 Swift 中尚不受支持。

Swift 处理的其他 C++ 特性

C++ 异常

Swift 可以与抛出异常的 C++ 代码互操作。但是,Swift 不支持捕获 C++ 异常。相反,当 C++ 代码未捕获的 C++ 异常到达 Swift 代码时,运行的程序将以致命错误终止。

对于任何未捕获的异常,Swift 的严格程序终止执行目前在 Windows 上使用 Swift 构建的 Swift 代码运行时不受支持。任何在 Windows 上运行的混合语言程序,当 C++ 异常传播穿过 Swift 代码时,都应始终终止,因为程序的堆栈将被展开。任何尝试从此类未捕获的异常中恢复的操作都可能导致程序中出现未定义的行为。

Clang 的可用性属性

使用 Clang 的可用性属性注解的 C++ API 在 Swift 中会接收相同的可用性注解。

支持的 Swift API

本节介绍哪些 Swift API 会在生成的头文件中暴露给 C++。

C++ 支持的 Swift 结构体

Swift 可以为大多数顶层 Swift 结构体生成 C++ 表示形式。以下 Swift 结构体目前尚不支持:

Swift 目前不向 C++ 暴露嵌套结构体。

C++ 支持的 Swift 类和 Actor

Swift 可以为大多数顶层 Swift 类和 Actor 生成 C++ 表示形式。以下 Swift 类目前尚不支持:

Swift 目前不向 C++ 暴露嵌套类和 Actor。

C++ 支持的 Swift 枚举

Swift 可以为大多数不具有关联值的顶层 Swift 枚举,以及一些具有关联值的顶层 Swift 枚举生成 C++ 表示形式。以下 Swift 枚举目前尚不支持:

此外,枚举的所有关联值的类型都必须可在 C++ 中表示。可表示类型的确切集合在下面描述可表示的参数或返回类型的部分中介绍。

Swift 目前不向 C++ 暴露嵌套枚举。

C++ 支持的 Swift 函数和属性

仅当 Swift 可以在 C++ 中表示其所有参数和返回类型时,任何函数、属性或初始化器才会暴露给 C++。仅当满足以下条件时,参数或返回类型才可以在 C++ 中表示:

具有未在上面列出的参数类型或返回类型的函数或初始化器目前无法在 C++ 中表示。类型未在上面列出的属性目前无法在 C++ 中表示。

此外,以下 Swift 函数、属性和初始化器目前还不能在 C++ 中表示:

支持的 Swift 标准库类型

Swift 能够在 C++ 中表示以下 Swift 标准库类型:

有关在 C++ 中使用 Swift 类型(如 String)的更多详细信息,请查看描述如何从 C++ 使用 Swift 标准库类型的部分。

请注意,C++ 目前不支持 Swift 元组。

C++ 支持的原始 Swift 类型列表

下表列出了 Swift 标准库中定义的可以在 C++ 中表示的原始 Swift 类型:

Swift 类型 对应的 C++ 类型
Bool bool
Int swift::Int
UInt swift::UInt
Int8 int8_t
Int16 int16_t
Int32 int32_t
Int64 int64_t
UInt8 uint8_t
UInt16 uint16_t
UInt32 uint32_t
UInt64 uint64_t
Float float
Double double
Float32 float
Float64 double
CBool bool
CChar char
CWideChar wchar_t
CChar16 char16_t
CChar32 char32_t
CSignedChar signed char
CShort short
CInt int
CLong long
CLongLong long long
CUnsignedChar unsigned char
CUnsignedShort unsigned short
CUnsignedInt unsigned int
CUnsignedLong unsigned long
CUnsignedLongLong unsigned long long
CFloat float
CDouble double

约束和限制

Swift 在 C++ 互操作性支持方面存在一些已知的限制。它们目前在 GitHub 上列出

Swift 包管理器约束

在 Swift 包管理器中启用 C++ 互操作性的 Swift 目标要求其依赖项也启用 C++ 互操作性。Swift GitHub 问题跟踪了此约束的状态

性能约束

Swift 当前对 C++ 容器类型的支持未提供明确的性能保证。最值得注意的是,当在 Swift 的 for-in 循环中使用集合时,Swift 可能会对集合进行深拷贝。

以下问题跟踪了此性能约束的状态

Swift 中使用 C 或 Objective-C API 的现有代码库的兼容性

在 Swift 中导入和使用 C 或 Objective-C API 的现有代码库中启用 C++ 互操作性可能会导致 Swift 中的一些源代码中断。尽管 C++ 在很大程度上与 C 源代码兼容,但在某些情况下 C++ 会有所不同。下面列出了一些可能导致 Swift 在 C++ 模式下无法导入 C 或 Objective-C 头文件的常见差异情况。

在这种情况下,建议您在 C 或 Objective-C 头文件中修复这些问题。如果这些头文件来自您无法控制的依赖项,则应向销售这些头文件的供应商报告问题。

一些使用平台 C 标准库中函数的现有代码库可能会遇到歧义错误,因为这些函数也在 C++ 标准库中定义。Swift 倾向于使用 C 标准库中的数学函数,如 sinpow。Swift 不知道的其他一些函数仍然可能导致错误。如果您遇到与平台 C 标准库中函数的歧义相关的此类错误,您可以通过在 Swift 中调用此类函数时使用显式的模块限定符来解决它。