Поддерживаемые возможности и ограничения межплатформенного взаимодействия C++
Swift поддерживает двустороннее взаимодействие с C++. На этой странице описываются поддерживаемые на данный момент функции взаимодействия с C++. Также здесь обсуждаются ограничения текущей поддержки межплатформенного взаимодействия с C++. Кроме того, здесь приведены ограничения, связанные с поддержкой взаимодействия с C++.
Взаимодействие с C++ — активно развивающаяся функция Swift. Определённые аспекты его дизайна и функциональности могут измениться в будущих версиях Swift, поскольку сообщество Swift собирает отзывы об использовании межплатформенного взаимодействия C++ в смешанных кодовых базах Swift и C++. Эта страница будет обновляться всякий раз, когда новая версия Swift изменяет поддерживаемые функции взаимодействия с C++.
Поддержка платформ
Взаимодействие с C++ поддерживается для разработки и развертывания на всех платформах, поддерживаемых Swift.
Минимальная версия развертывания для приложений со смешанными языками
Взаимодействие с C++ не накладывает дополнительных требований к версии развертывания для вашего приложения, за исключением случаев, когда ваш код Swift использует классы или структуры C++, которые становятся ссылками. Минимальная версия развертывания для приложения, не использующего такие типы ссылок, совпадает с обычной минимальной версией развертывания Swift .
Минимальная версия развертывания для ссылочных типов, импортированных из C++
В таблице ниже показана минимальная версия ОС, для которой можно развернуть приложение со смешанным кодом Swift и C++, использующее классы или структуры C++, которые становятся ссылками. Любая платформа развертывания, не указанная в таблице ниже, поддерживается автоматически, поэтому импортированные ссылочные типы не накладывают дополнительных требований к версии развертывания для таких платформ, как Ubuntu или CentOS.
| Платформа, на которой выполняется приложение Swift | Минимальная версия развертывания |
|---|---|
| macOS | 13.3 |
| iOS | 16.4 |
| watchOS | 9.4 |
| tvOS | 16.4 |
Поддержка компилятора
Взаимодействие с C++ поддерживается в Swift 5.9 и выше.
Поддержка Swift двустороннего взаимодействия основана на заголовке, сгенерированном компилятором Swift, который затем может быть включён кодом C++, желающим использовать Swift API. Этот заголовок использует специфические для Swift расширения компилятора, которые поддерживаются только следующими компиляторами C++:
- Clang (начиная с LLVM 11 и выше)
- Apple Clang
Код C++, скомпилированный другими компиляторами, не может вызывать Swift-функции или использовать Swift-типы из C++.
Поддержка стандартной библиотеки C++
Компилятор Swift использует стандартную библиотеку C++ платформы при взаимодействии с C++. В этой таблице показано, какая стандартная библиотека C++ используется при построении кода Swift для определённой платформы развертывания:
| Платформа, на которой выполняется приложение Swift | Стандартная библиотека C++ по умолчанию |
|---|---|
| Платформы Apple | libc++ |
| Ubuntu, CentOS, Amazon Linux | libstdc++ |
| Windows | Стандартная библиотека C++ Microsoft (msvcprt) |
Swift в настоящее время не поддерживает выбор альтернативной стандартной библиотеки для платформ, поддерживающих альтернативные стандартные библиотеки. Например, вы не можете использовать libc++ при построении кода Swift для Ubuntu, даже если libc++ может использоваться при построении кода C++ для Ubuntu.
Смешанный код Swift и C++ должен использовать одну и ту же стандартную библиотеку C++.
Использование взаимодействия с C++ требует компилятора с включённой поддержкой стандарта C++14 или более новой версии. Swift позволяет изменить, какую версию стандарта C++ использовать; однако, заголовки библиотек C++, используемые из Swift, также должны соответствовать выбранному стандарту C++. При использовании двустороннего взаимодействия программы необходимо компилировать с поддержкой C++14, так как сгенерированный C++ интерфейс для модуля Swift использует возможности C++14.
Настройка версии стандарта C++
Вот как установить версию стандарта C++, используемого для взаимодействия компилятором Swift:
- При компиляции зависимостей пакета версия стандарта C++ может быть настраиваема в
Package.swiftс помощью параметраcxxLanguageStandardв вашемPackage(...). - Для целей Xcode вы можете выбрать используемый стандарт C++ из настроек «Диалект языка C++» во вкладке «Настройки сборки».
- Если вы используете другую систему сборки или вызываете компилятор Swift напрямую из командной строки, вы можете указать версию стандарта C++ с помощью опции
-Xcc -std=, например,-Xcc -std=c++20.
Поддерживаемые API C++
Поддерживаемые в Swift функции C++
Swift поддерживает вызов большинства нешаблонных:
- Функций верхнего уровня
- Функций внутри пространств имён
- Член-функций, как экземпляров, так и статических
- Виртуальных член-функций типов C++, которые становятся ссылками
- Конструкторов
- Операторов
- Арифметических операторов, таких как
operator+,operator-,operator* - Оператора прединкремента
operator++представлен какfunc successor() -> Self - Оператора вызова
T operator(Param p)представлен какfunc callAsFunction(p: Param) -> T - Оператора преобразования булевого литерала
operator boolпредставлен как удобный инициализаторBool(fromCxx:)
- Арифметических операторов, таких как
Функции и конструкторы, использующие типы r-value ссылок, пока недоступны в Swift.
Swift поддерживает вызов некоторых шаблонных функций C++. Любая функция или шаблон функции, использующие зависимый тип в своей сигнатуре или универсальную ссылку (T &&), недоступна в Swift. Любой шаблон функции с параметрами шаблона, отличными от типов, недоступен в Swift. Шаблоны функций с переменным числом аргументов недоступны в Swift.
Функция C++, тип возвращаемого значения которой не поддерживается в Swift, или с параметром, тип которого не поддерживается в Swift, недоступна в Swift.
Если параметр функции C++ имеет значение по умолчанию, параметр также будет иметь значение по умолчанию в Swift, если:
- Функция не является конструктором
- Параметр не является
inoutв Swift - Параметр не является указателем
- Параметр не является константной ссылкой
Поддерживаемые в Swift типы C++
- Примитивные типы, такие как
intиbool - Указатели
- C++ ссылки, за исключением параметров r-value ссылок/универсальных ссылок
- Алиасы типов, только если базовый тип поддерживается в Swift
- Копируемые структуры и классы
- Перемещаемые некопируемые структуры и классы
- Перечисления, включая перечисления со областью действия (
enum class)
Типы C++, которые становятся значениями в Swift, могут создаваться и передаваться по значению.
Типы C++, которые становятся ссылками в Swift, не могут быть созданы напрямую кодом Swift. Они могут свободно передаваться между Swift и C++.
Типы C++, определённые внутри C++ namespace, доступны в Swift.
Шаблоны классов и структур напрямую недоступны в Swift. Инициализированные специализации классов или структур шаблонов доступны в Swift. Код Swift может получить доступ к типам специализации шаблона, используя алиас типа, определённый в заголовке C++.
Публичные члены данных структуры или класса C++ доступны в Swift, когда тип такого члена данных поддерживается в Swift.
Поддерживаемые в Swift типы стандартной библиотеки C++
Следующие типы стандартной библиотеки C++ поддерживаются в Swift:
-
std::string,std::u16string,std::u32string - Специализации
std::pair - Специализации
std::vector - Специализации
std::mapиstd::unordered_map - Специализации
std::set,std::multisetиstd::unordered_set - Специализации
std::optional - Специализации
std::shared_ptr - Специализации
std::array
Другие типы стандартной библиотеки, такие как std::unique_ptr, std::function и std::variant, пока не поддерживаются в Swift.
Другие возможности C++ обрабатываемые Swift
Исключения C++
Swift может взаимодействовать с кодом C++, который вызывает исключения. Однако Swift не поддерживает перехват исключений C++. Вместо этого работающая программа завершается с ошибкой fatal, когда исключение C++, которое не перехвачено кодом C++, достигает кода Swift.
Строгое завершение программы Swift для любых неперехваченных исключений в настоящее время не поддерживается при выполнении кода Swift, построенного с помощью Swift на Windows. Любая программа смешанного языка, работающая на Windows, всегда должна завершаться, когда исключение C++ распространяется через код Swift, поскольку стек программы разворачивается. Любая попытка восстановиться из такого неперехваченного исключения может привести к неопределенному поведению в вашей программе.
Атрибуты доступности Clang
C++ API, аннотированные атрибутами доступности Clang, получают те же аннотации доступности в Swift.
Поддерживаемые Swift API
В этом разделе описывается, какие Swift API экспонируются для C++ в сгенерированном заголовке.
Swift структуры, поддерживаемые C++
Swift может сгенерировать представление C++ для большинства основных Swift структур. Следующие Swift структуры пока не поддерживаются:
- Структуры нулевого размера, которые не имеют хранимых свойств
- Некопируемые структуры
- Обобщенные структуры с обобщенными ограничениями или более чем тремя обобщенными параметрами или имеющие вариативные обобщения
В настоящее время Swift не экспонирует вложенные структуры для C++.
Swift классы и акторы, поддерживаемые C++
Swift может сгенерировать представление C++ для большинства основных Swift классов и акторов. Следующие Swift классы пока не поддерживаются:
- Обобщенные классы и акторы
В настоящее время Swift не экспонирует вложенные классы и акторы для C++.
Swift перечисления, поддерживаемые C++
Swift может сгенерировать представление C++ для большинства основных Swift перечислений, у которых нет связанных значений, и некоторых основных Swift перечислений, у которых есть связанные значения. Следующие Swift перечисления пока не поддерживаются:
- Некопируемые перечисления
- Обобщенные перечисления с обобщенными ограничениями или более чем тремя обобщенными параметрами или имеющие вариативные обобщения
- Перечисления, у которых есть случай перечисления со связанным значением более чем одного
- Косвенные перечисления
Кроме того, типы всех связанных значений перечисления должны быть представимыми в C++. Точный набор представимых типов описан ниже, в разделе, описывающем представимые параметры или возвращаемые типы.
В настоящее время Swift не экспонирует вложенные перечисления для C++.
Swift функции и свойства, поддерживаемые C++
Любая функция, свойство или инициализатор экспонируется в C++ только тогда, когда Swift может представить все её параметры и возвращаемые типы в C++. Тип параметра или возвращаемого значения может быть представлен в C++ только тогда, когда:
- это поддерживаемая Swift структура/класс/перечисление, определённая в том же Swift модуле.
- или это C++ структура/класс/перечисление, которое не помечено как тип ссылки.
- или это один из поддерживаемых типов Swift стандартной библиотеки.
- если это обобщенный тип, например
Array, его обобщенные параметры должны быть связаны с одним из типов, перечисленных здесь.
- если это обобщенный тип, например
- или это
UnsafePointer/UnsafeMutablePointer/Optional<UnsafePointer>/Optional<UnsafeMutablePointer>, указывающее на любой тип из трёх поддерживаемых категорий типов, перечисленных выше.
Функции или инициализаторы, у которых тип параметра или возвращаемого значения не указаны выше, пока не могут быть представлены в C++. Свойства типа, который не указан выше, пока не могут быть представлены в C++.
Кроме того, следующие Swift функции, свойства и инициализаторы пока не могут быть представлены в C++:
- Асинхронные функции/свойства
- Функции/свойства/инициализаторы, которые
throw - Обобщённые функции/свойства/инициализаторы с обобщёнными ограничениями или вариативными обобщениями
- Функции, возвращающие непрозрачный тип
- Функции, возвращающие несколько значений
- Функции/свойства/инициализаторы с атрибутом
@_alwaysEmitIntoClient
Поддерживаемые Swift типы стандартной библиотеки
Swift может представить следующие типы Swift стандартной библиотеки в C++:
- Примитивные типы, такие как
Bool,Int,Floatи их C аналоги, такие какCInt- Полный список поддерживаемых примитивных типов указан ниже.
- Типы указателей, такие как
OpaquePointer,UnsafePointer,UnsafeMutablePointer,UnsafeRawPointerиUnsafeMutableRawPointer -
Stringтип -
Arrayтип -
Optionalтип
Для получения более подробной информации об использовании Swift типов, таких как String в C++, ознакомьтесь с разделом, описывающим, как использовать типы Swift стандартной библиотеки из C++.
Обратите внимание, что кортежи Swift в настоящее время не поддерживаются в C++.
Список примитивных Swift типов, поддерживаемых C++
В этой таблице перечислены примитивные типы Swift, определенные в стандартной библиотеке Swift, которые могут быть представлены в C++:
| Swift Type | Corresponding C++ type |
|---|---|
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 Package Manager
Целевой Swift, который включает взаимодействие с C++ в Swift Package Manager требует, чтобы его зависимости также включали взаимодействие с C++. Статус этого ограничения отслеживается в проблеме Swift GitHub:
Ограничения производительности
Текущая поддержка Swift для типов контейнеров C++ не предоставляет явных гарантий производительности. Наиболее заметно, что Swift может выполнить глубокую копию коллекции, когда она используется в цикле for-in в Swift.
Следующая проблема отслеживает статус этого ограничения производительности:
Совместимость с существующими кодовыми базами, которые используют API C или Objective-C в Swift
Включение взаимодействия с C++ в существующей кодовой базе, которая импортирует и использует API C или Objective-C в Swift, может привести к некоторым проблемам в исходном коде Swift. Несмотря на то, что C++ в значительной степени совместим с C по исходному коду, есть несколько случаев, когда C++ отличается. Ниже приведены некоторые распространённые случаи различий, которые могут привести к тому, что Swift не сможет импортировать заголовки C или Objective-C в режиме C++:
- C++ использует более широкий набор ключевых слов, которые могут конфликтовать с существующими API C или Objective-C. Например, функция C, один из параметров которой назван
class, не является допустимой функцией C++. - Существующие заголовки C или Objective-C могут попытаться импортировать другой модуль Clang внутри блока
extern "C". Это не разрешается в режиме C++.
В таких случаях рекомендуется исправить эти проблемы в ваших заголовках C или Objective-C. Если эти заголовки поступают от зависимости, которой вы не управляете, вам следует сообщить об этой проблеме поставщику этих заголовков.
В некоторых существующих кодовых базах, использующих функции из стандартной библиотеки C платформы, могут возникнуть ошибки неоднозначности, связанные с тем, что такие функции также определены в стандартной библиотеке C++. Swift предпочитает использовать математические функции, такие как sin и pow из стандартной библиотеки C. Некоторые другие функции, о которых Swift не знает, всё ещё могут вызвать ошибку. В тех случаях, когда вы видите такую ошибку, связанную с неоднозначностью функции из стандартной библиотеки C платформы, вы можете разрешить её, используя явный квалификатор модуля из Swift при вызове такой функции.
The Swift Programming Language, Copyright © 2014-2025 Apple Inc.
Swift and the Swift logo are trademarks of Apple Inc.
Documentation for Swift 6.0.3
https://www.swift.org/documentation/cxx-interop/status