Mixing Swift and C++
Table of Contents
- Introduction
- Overview
- Using C++ Types and Functions in Swift
- Customizing How C++ Maps to Swift
- Extending C++ Types in Swift
- Working with C++ Containers
- Mapping C++ Types to Swift Reference Types
- Using C++ Standard Library from Swift
- Working with C++ References and View Types in Swift
- Accessing Swift APIs from C++
- Using Swift Types and Functions from C++
- Using Swift Standard Library Types from C++
- Appendix
- Document Revision History
Introduction
This document is the reference guide describing how to mix Swift and C++. It describes how C++ APIs get imported into Swift, and provides examples showing how various C++ APIs can be used in Swift. It also describes how Swift APIs get exposed to C++, and provides examples showing how the exposed Swift APIs can be used from C++.
C++ interoperability is a new feature in the upcoming Swift 5.9 release. A pre-release Swift toolchain that supports C++ interoperability can be downloaded on the Swift website.
C++ interoperability is an actively evolving feature of Swift. It currently supports interoperation between a subset of language features. The status page provides an overview of the currently supported interoperability features, and lists the existing constraints as well.
Future releases of Swift might change how Swift and C++ interoperate, as the Swift community gathers feedback from real world adoption of C++ interoperability in mixed Swift and C++ codebases. Please provide the feedback that you have on the Swift forums, or by filing an issue on GitHub. Future changes to the design or functionality of C++ interoperability will not break code in existing codebases by default.
Overview
This section provides a high-level overview of how to mix Swift and C++. You can get started by enabling C++ interoperability in Swift. You will then want to understand how Swift imports C++ headers, and how the imported C++ types and functions are represented by the Swift compiler. After that, you will want to look over the follow-up sections that describe how to use the imported C++ APIs in Swift. You should also take a look at how Swift APIs can be exposed to the rest of your C++ codebase. If you’re interested in using Swift APIs from C++, you will definitely want to look over the follow-up sections that describe how to use the exposed Swift APIs in C++.
Enabling C++ Interoperability
Swift code interoperates with C and Objective-C APIs by default. You must enable interoperability with C++ if you want to use C++ APIs from Swift, or expose Swift APIs to C++.
The following guides describe how C++ interoperability can be enabled when working with a specific build system or IDE:
- Read how to use C++ APIs from Swift in a Swift package
- Read how to mix Swift and C++ in an Xcode project
Other build systems can enable C++ interoperability by passing in the required flag to the Swift compiler:
Importing C++ into Swift
Header files are commonly used to describe the public interface of a C++ library. They contain type and template definitions, and also declarations for functions and methods, whose bodies are often placed into implementation files that are then compiled by the C++ compiler.
The Swift compiler embeds the Clang compiler.
This allows Swift to import C++ header files using
Clang modules. Clang modules
provide a more robust and efficient semantic model of C++ headers as
compared to the preprocessor-based model of directly including the contents of
header files using the #include
directive.
Swift currently cannot import C++ modules introduced in the C++20 language standard.
Creating a Clang Module
In order for Swift to import a Clang module, it needs to find a
module.modulemap
file that describes how a collection of C++ headers maps
to a Clang module.
Some IDEs and build systems can generate a module map file for a C++ build target automatically. Swift Package Manager automatically generates a module map file when it finds an umbrella header in a C++ target. Xcode automatically generates a module map file for a framework target, with the module map referencing framework’s public headers. In other cases you might be required to create a module map manually.
The recommended way to manually create a module map is to list all the header
files from a specific C++ target that you want to make available to Swift.
For example, let’s say we want to create a module map for a C++
library forestLib
. This library has two header files: forest.h
and tree.h
.
In this case we can follow the recommended approach and create a module map
that has two header
directives:
module forestLib {
header "forest.h"
header "tree.h"
export *
}
The export *
directive is another
recommended addition to the module map.
It ensures that the types from Clang modules imported
into the forestLib
module are visible to Swift as well.
The module map file should be placed right next to the header files it
references.
For example, in the forestLib
library, the module map would
go into the include
directory:
forestLib
├── include
│ ├── forest.h
│ ├── tree.h
│ └── module.modulemap [NEW]
├── forest.cpp
└── tree.cpp
Now that forestLib
has a module map, Swift can import it when
C++ interoperability is enabled. In order for Swift to find the forestLib
module, the build system must pass the import path flag (-I
) that
points to forestLib/include
when it’s invoking the Swift compiler.
For more information on the syntax and the semantics of module map files, please see Clang’s module map language documentation.
Working with Imported C++ APIs
The Swift compiler represents the imported C++ types and functions using Swift declarations once a Clang module is imported. This allows Swift code to use C++ types and functions as if they were Swift types and functions.
For example, Swift can represent the following C++ enumeration and
the following C++ class from the forestLib
library:
enum class TreeKind {
Oak,
Redwood,
Willow
};
class Tree {
public:
Tree(TreeKind kind);
private:
TreeKind kind;
};
A Swift enumeration is used internally by the Swift compiler to represent TreeKind
:
enum TreeKind : Int32 {
case Oak = 0
case Redwood = 1
case Willow = 2
}
A Swift structure is used internally by the Swift compiler to represent Tree
:
struct Tree {
init(_ kind: TreeKind)
}
Such structure can be used directly in Swift, just like any other Swift structure:
import forestLib
let tree = Tree(.Oak)
Swift uses C++ types and
calls C++ functions directly, without any kind of indirection or wrapping.
In the example shown above,
Swift directly calls the C++ constructor for class Tree
, and stores the
resulting object directly into the tree
variable.
A subsequent section of this guide provides more details on how to use the imported C++ APIs in Swift.
Exposing Swift APIs to C++
In addition to importing and using C++ APIs, the Swift compiler is also capable of exposing Swift APIs from a Swift module to C++. This makes it possible to gradually integrate Swift into an existing C++ codebase.
Swift APIs can be accessed by including a header file that the build system generates when building a Swift module. Some build systems generate the header automatically. Xcode can automatically generate the header file for a framework or an App target. Other build configurations can generate the header manually by following the steps outlined on the project and build setup page.
The generated header uses C++ types and functions to represent Swift types and functions. When C++ interoperability is enabled, Swift generates C++ bindings for all the supported public types and functions in a Swift module. For example, the following Swift function can be called from C++:
// Swift module 'forestRenderer'
import forestLib
public func renderTreeToAscii(_ tree: Tree) -> String {
...
}
An inline C++ function that calls the implementation of renderTreeToAscii
directly will be present in the header generated by the Swift compiler for the
forestRenderer
module. It can be called from C++ code once the C++
file includes the generated header:
#include "forestRenderer-Swift.h"
#include <string>
#include <iostream>
void printTreeArt(const Tree &tree) {
std::cout << (std::string)forestRenderer::renderTreeToAscii(tree);
}
The C++ interoperability status page describes which Swift language constructs and standard library types can be exposed to C++. Some unsupported Swift APIs are mapped to empty unavailable C++ declarations in the generated header, so you’ll get an error in the C++ code when you try to use something that’s not exposed to C++.
Source Stability Guarantees for Mixed-Language Codebases
The way Swift interoperates with C++ is still evolving. Some changes in future releases of Swift will require source changes in mixed Swift and C++ codebases that have already adopted C++ interoperability. However, Swift will not force you to adopt new or evolved C++ interoperability features when adopting a new version of the Swift toolchain. To make that possible, future Swift releases will provide multiple compatibility versions of C++ interoperability, just like Swift provides support for multiple compatibility versions of the base Swift language. This means that a project using the current compatibility version of C++ interoperability will be insulated from any changes made in subsequent releases, and it can move to newer compatibility versions at its own pace.
Using C++ Types and Functions in Swift
A wide array of C++ types and functions can be used directly from Swift. This section goes over the fundamentals of how the supported types and functions can be used from Swift.
Calling C++ Functions
C++ functions from imported modules can be called using the familiar function call syntax from Swift. For example, this C++ function is available in Swift:
void printWelcomeMessage(const std::string &name);
Swift code can call such function as if it was a regular Swift function:
printWelcomeMessage("Thomas")
C++ Structures and Classes are Value Types by Default
Swift maps C++ structures and classes to Swift struct
types by default.
Swift considers them to be
value types. This means that they’re always copied
when they’re passed around in your Swift code.
The special members of a C++ structure or class type are used by Swift when it needs to perform a copy of a value or dispose of a value when it goes out of scope. If the C++ type has a copy constructor, Swift will use it when a value of such type is copied in Swift. And if the C++ type has a destructor, Swift will call the destructor when a Swift value of such type is destroyed.
Currently C++ structures and classes with a deleted copy constructor are not available in Swift. Non-copyable C++ structures or classes that also have a move constructor will be available in a future version of Swift.
Some C++ types are always passed around using a pointer or a reference in C++. As such it might not make sense to map them to value types in Swift. These types can be annotated in C++ to instruct the Swift compiler to map them to reference types in Swift instead.
Constructing C++ Types from Swift
Public constructors inside C++ structures and classes that aren’t copy or move constructors become initializers in Swift.
For example, all three constructors of the C++ Color
class are
available in Swift:
class Color {
public:
Color();
Color(float red, float blue, float green);
Color(float value);
...
float red, blue, green;
};
The Color
constructors shown above become initializers in Swift.
Swift code can call them to create a value of type Color
:
let theEmptiness = Color()
let oceanBlue = Color(0.0, 0.0, 1.0)
let seattleGray = Color(0.7)
Accessing Data Members of a C++ Type
The public data members of C++ structures and classes become properties
in Swift. For example, the data members of the Color
class shown above
can be accessed just like any other Swift property:
let color: Color = getRandomColor()
print("Today I'm feeling \(color.red) red but also \(color.blue) blue")
Calling C++ Member Functions
Member functions inside C++ structures and classes become methods in Swift.
Constant Member Functions Are nonmutating
Constant member functions become nonmutating
Swift methods, whereas
member function without a const
qualifier become mutating
Swift methods.
For example, this member function in the C++ Color
class
is considered to be a mutating
method in Swift:
void Color::invert() { ... }
Mutable Color
values can call invert
:
var red = Color(1.0, 0.0, 0.0)
red.invert() // red becomes yellow.
Constant Color
values cannot call invert
.
On the other hand, this constant member function is not a mutating
method in
Swift:
Color Color::inverted() const { ... }
Therefore constant Color
values can call inverted
:
let darkGray = Color(0.2, 0.2, 0.2)
let veryLightGray = darkGray.inverted()
Constant Member Functions Must Not Mutate the Object
The Swift compiler assumes that constant member functions do not
mutate the instance that this
points to. A violation of this assumption by a
C++ member function could lead to Swift code not observing the mutation
of the instance pointed to by this
and using the original value of such
instance for the rest of the Swift code execution.
C++ permits the mutation of mutable
fields in constant member functions.
Constant member functions in structures or classes with such fields
still become nonmutating
methods in Swift. Swift doesn’t know which
constant functions mutate the object, and which don’t, so for the sake
of better API usability Swift still assumes that such functions do not
mutate the object. You should avoid calling constant member functions
that mutate mutable
fields from Swift, unless they’re explicitly annotated with a SWIFT_MUTATING
macro.
Swift 5.9 will ship with a
SWIFT_MUTATING
customization macro. However, it’s not yet available in a downloadable Swift 5.9 toolchain. This macro will allow you to explicitly annotate constant member functions that do mutate the object. Such functions with then becomemutating
methods in Swift. The following GitHub issue tracks the status ofSWIFT_MUTATING
support in Swift.
Member Functions Returning References Are Unsafe by Default
Member functions that return references, pointers, or
certain structures/classes that contain references or pointers
often return a reference that points inside of this
, the object
used to call the function.
Such member functions are considered to be unsafe in Swift,
as the returned reference
is not associated with the owning object which can get
destroyed while the reference is still in use. Swift automatically
renames such member functions in order to emphasize their unsafety.
Their Swift name is prefixed
with two underscores and suffixed with Unsafe
. For example, the following
member function becomes the __getRootTreeUnsafe
method in Swift:
class Forest {
public:
const Tree &getRootTree() const { return rootTree; }
...
private:
Tree rootTree;
};
The set of rules that determine which functions are unsafe, and the recommended guidelines for calling such methods safely from Swift are documented in an upcoming section that describes how to safely work with C++ references and view types in Swift.
Overloaded Member Functions
C++ allows member functions to be overloaded based on their const
qualifier.
For example, the Forest
class can have two getRootTree
members, that differ
only in their constness and their return type:
class Forest {
public:
const Tree &getRootTree() const { return rootTree; }
Tree &getRootTree() { return rootTree; }
...
private:
Tree rootTree;
};
The two getRootTree
member functions become methods in Swift. Swift
renames the mutating
method to avoid having two ambiguous methods with
the same name and arguments, when it finds that the type already has a
nonmutating
method with the same Swift name. The rename appends
the Mutating
suffix to the name of the mutating
method.
This rename is done before the safety of the method is taken into account.
In the example shown above,
the two getRootTree
member functions become
__getRootTreeUnsafe
and __getRootTreeMutatingUnsafe
methods in Swift,
because they return a reference that points into the Forest
object.
Virtual Member Functions
Currently virtual member functions are not available in Swift.
Static Member Functions
Static C++ member functions become static
Swift methods.
Accessing Inherited Members from Swift
A C++ class or structure becomes a standalone type in Swift. Its relationship with base C++ classes is not preserved in Swift. Swift tries its best to provide access to the members inherited from base classes of a C++ type. The public member functions and data members from a C++ base class become methods and properties in Swift, as if they were defined in the specific class itself.
For example, the following two C++ classes become two distinct Swift structures:
class Plant {
public:
void water(float amount) { moisture += amount; }
private:
float moisture = 0.0;
};
class Fern: public Plant {
public:
void trim();
};
The Fern
Swift structure gets an additional method named water
, that
calls member function water
in the Plant
C++ class:
struct Plant {
mutating func water(_ amount: Float)
}
struct Fern {
init()
mutating func water(_ amount: Float) // Calls `Plant::water`
mutating func trim()
}
The exact rules that determine when members from inherited base types are introduced to the Swift type that represents the C++ structure or class are not yet finalized in Swift 5.9. The following GitHub issue tracks their finalization in Swift 5.9.
Using C++ Enumerations
Scoped C++ enumerations become Swift enumerations with raw values. All of their cases get mapped to Swift cases as well. For example, the following C++ enumeration is available in Swift:
enum class TreeKind {
Oak,
Redwood,
Willow
};
It is represented in Swift as the following enumeration:
enum TreeKind : Int32 {
case Oak = 0
case Redwood = 1
case Willow = 2
}
It can be used just like any other enum
in Swift:
func isConiferous(treeKind: TreeKind) -> Bool {
switch treeKind {
case .Redwood: return true
default: return false
}
}
Unscoped C++ enumerations become Swift structures. For example, the following
unscoped enum
becomes a Swift structure:
enum MushroomKind {
Oyster,
Portobello,
Button
}
The cases of unscoped C++ enumerations become variables outside of the Swift structure:
struct MushroomKind : Equatable, RawRepresentable {
public init(_ rawValue: UInt32)
public init(rawValue: UInt32)
public var rawValue: UInt32
}
var Oyster: MushroomKind { get }
var Portobello: MushroomKind { get }
var Button: MushroomKind { get }
Using C++ Type Aliases
A C++ using
or typedef
declaration becomes a typealias
in Swift.
For instance, the following using
declaration becomes a CustomString
type in Swift:
using CustomString = std::string;
Using Class Templates
An instantiated specialization of a class or structure template is mapped to a distinct type in Swift. For example, the following uninstantiated C++ class template is not available in Swift by itself:
template<class T, class U>
class Fraction {
public:
T numerator;
U denominator;
Fraction(const T &, const U &);
};
However,
an instantiated specialization of a class template is available in Swift.
it is treated like
a regular C++ structure or class when it is mapped into Swift. For
example, the Fraction<int, float>
template specialization becomes a
Swift structure:
struct Fraction<CInt, Float> {
var numerator: CInt
var denominator: Float
init(_: CInt, _: Float)
}
A function that returns a specialization like Fraction<int, float>
is available in Swift:
Fraction<int, float> getMagicNumber();
Such function can be called from Swift like any other Swift function:
let magicNum = getMagicNumber()
print(magicNum.numerator, magicNum.denominator)
A C++ type alias can refer to a specific specialization of a
class template. For example, in order to construct
Fraction<int, float>
from Swift, you first want to create a
C++ type alias that refers to such template specialization:
// Bring `Fraction<int, float>` type to Swift with a C++ `using` declaration.
using MagicFraction = Fraction<int, float>;
Then you can use this type alias directly from Swift:
let oneEights = MagicFraction(1, 8.0)
print(oneEights.numerator)
A follow-up section of this document describes how Swift generics and protocol extensions can be used to write generic Swift code that works with any specialization of a class template.
Customizing How C++ Maps to Swift
The defaults that determine how C++ types and functions map to Swift can be
changed by annotating a specific C++
function or type with one of the provided customization macros. For example,
you can choose to provide a different Swift name for a specific C++
function using the SWIFT_NAME
macro.
The <swift/bridging>
header defines the customization macros that can be used
to annotate C++ functions and types. This header ships with the
Swift toolchain.
On Apple and Linux platforms both the system’s C++ compiler and the Swift compiler should find this header automatically. On other platforms, like Windows, you might need to add additional header search path flags (
-I
) to your C++ and Swift compiler invocations to make sure that this header is found.
This section describes just two of the customization macros from
the <swift/bridging>
header. The other customization macros and their
behavior are documented in the subsequent sections in this document.
The complete list of all the
customization macros is provided in the appendix.
Renaming C++ APIs in Swift
The SWIFT_NAME
macro provides a different name for C++
types and functions in Swift. C++ types can be renamed by specifying the Swift
type name inside of the SWIFT_NAME
macro. For example,
the following C++ class gets renamed to CxxLibraryError
structure in Swift:
class Error {
...
} SWIFT_NAME("CxxLibraryError");
When renaming a function, you need to specify the Swift function name
(including argument labels) inside of the SWIFT_NAME
macro.
For example, the following C++ function gets renamed to send
in Swift:
#include <swift/bridging>
void sendCopy(const std::string &) SWIFT_NAME(send(_:));
You must use the new name when calling such function from Swift:
send("Hello, this is Swift!")
Mapping Getters and Setters to Computed Properties
The SWIFT_COMPUTED_PROPERTY
macro maps a C++ getter and setter member
function to a computed property in Swift. For example, the following getter
and setter pair is mapped to a single treeKind
computed property in Swift:
#include <swift/bridging>
class Tree {
public:
TreeKind getKind() const SWIFT_COMPUTED_PROPERTY;
void setKind(TreeKind kind) SWIFT_COMPUTED_PROPERTY;
...
};
Such property can be mutated in Swift as it has a setter:
func makeNotAConiferousTree(tree: inout Tree) {
tree.kind = tree.kind == .Redwood ? .Oak : tree.kind
}
Both the getter and setter need to operate on the same underlying C++ type for this transformation to be successful in Swift.
It’s possible to map just the getter to a computed property, a setter is not required for this transformation to work.
Extending C++ Types in Swift
Swift extensions can add new functionality to C++ types in Swift. They can also conform an existing C++ type to a Swift protocol.
Extensions can add new functionality to a C++ type, but they can’t override existing functionality of a C++ type.
Conforming C++ Type to Swift Protocol
Swift protocol conformance can be added to a C++ type retroactively (after the type has been defined). Such conformance enables the following use cases in Swift:
- Generic Swift functions and types constrained by protocols can work with a conforming C++ value.
- A protocol type can represent a conforming C++ value.
For example, a Swift extension can add
Hashable
conformance to the C++ class Tree
:
extension Tree: Hashable {
static func == (lhs: Tree, rhs: Tree) -> Bool {
return lhs.kind == rhs.kind
}
func hash(into hasher: inout Hasher) {
hasher.combine(self.kind.rawValue)
}
}
Such conformance then lets you use Tree
as a key in a Swift dictionary:
let treeEmoji: Dictionary<Tree, String> = [
Tree(.Oak): "🌳",
Tree(.Redwood): "🌲"
]
Conforming Class Template to Swift Protocol
A Swift extension can add protocol conformance to a specific class template specialization in Swift. For example, instantiated specializations of the following class template are available in Swift:
template<class T>
class SerializedValue {
public:
T deserialize() const;
...
};
using SerializedInt = SerializedValue<int>;
using SerializedFloat = SerializedValue<float>;
SerializedInt getSerializedInt();
SerializedFloat getSerializedFloat();
Such template specializations can conform to a protocol using a Swift
extension
:
// Swift module 'Serialization'
protocol Deserializable {
associatedtype ValueType
func deserialize() -> ValueType
}
// `SerializedInt` specialization now conforms to `Deserializable`
extension SerializedInt: Deserializable {}
In the example above SerializedInt
conforms to the Deserializable
protocol.
However, other specializations of the class template, like SerializedFloat
,
do not conform to Deserializable
.
The SWIFT_CONFORMS_TO
customization macro from the <swift/bridging>
header can be used to conform all specializations of a class template to
a Swift protocol automatically. For example, the
definition of the SerializedValue
class template can be annotated with
SWIFT_CONFORMS_TO
:
template<class T>
class SerializedValue {
public:
using ValueType = T;
T deserialize() const;
...
} SWIFT_CONFORMS_TO(Serialization.Deserializable);
The SWIFT_CONFORMS_TO
annotation makes all specializations,
like SerializedInt
and SerializedFloat
,
conform to Deserializable
automatically in Swift. This makes it possible
to add functionality to all specializations of a class
template in Swift, by using a protocol extension:
extension Deserializable {
// All specializations of the `SerializedValue` template now have
// `deserializedDescription` property in Swift.
var deserializedDescription: String {
"serialized value \(deserialize().description)"
}
}
This also lets you use any specialization in constrained generic code without any additional explicit conformances:
func printDeserialized<T: Deserializable>(_ item: T) {
print("obtained: \(item.deserializedDescription)")
}
// Both `SerializedInt` and `SerializedFloat` specializations automatically
// conform to `Deserializable`
printDeserialized(getSerializedInt())
printDeserialized(getSerializedFloat())
Working with C++ Containers
C++ container types, like the std::vector
class
template,
typically provide iterator-based APIs for users in C++.
Using a C++ iterator is unsafe
in Swift, as such use is not
associated with its owning container which can get destroyed
while the iterator is still in use.
Instead of relying on C++ iterators, Swift automatically
conforms some C++ container types to protocols that:
- Allow safe access to the underlying container in Swift using standard Swift APIs.
- Provide a way to convert a C++ container to a Swift collection type.
These protocols and their conformance rules are described below. The recommended approach for using C++ containers that conform to these protocols is summarized in a follow-up section.
Some C++ Containers Are Swift Collections
Swift conforms C++ containers that provide random access to their
elements, like std::vector
, to Swift’s RandomAccessCollection
protocol
automatically. For example, the std::vector
container returned by this
function is conformed to the RandomAccessCollection
protocol
automatically by Swift:
std::vector<Tree> getEnchantedTrees();
The conformance to RandomAccessCollection
makes it possible to traverse
through the container’s elements safely in Swift, using familiar control
flow statements like the for-in
loop. Collection methods like map
and filter
are also available:
let trees = getEnchantedTrees()
// Traverse through the elements of a C++ vector.
for tree in trees {
print(tree.kind)
}
// Filter the C++ vector and make a Swift Array that contains only
// the oak trees.
let oakTrees = getEnchantedTrees().filter { $0.kind == .Oak }
Swift’s count property returns the number of elements in such collection. Swift’s subscript operator can be used to access a specific element in the collection as well. This makes it possible to mutate individual elements in the C++ container:
var trees = getEnchantedTrees()
for i in 0..<trees.count {
trees[i].kind = .Oak
}
A C++ container that conforms to RandomAccessCollection
can be easily
converted into a Swift collection type, like Array
:
let treesArray = Array<Tree>(getEnchantedTrees())
Swift does not convert C++ container types to Swift collection types
automatically. Any conversion from a C++ container type, like std::vector
,
to a Swift collection type, like Array
, is explicit in Swift.
Performance Constraints of Automatic Collection Conformance
Swift currently does not provide explicit performance guarantees when
using C++ containers that conform to RandomAccessCollection
. Swift
will most likely make a deep copy of the container when:
- The container is used in a
for-in
loop. - The container is used with methods like
filter
andreduce
whose implementation comes from Swift’sSequence
protocol.
This constraint is tracked on the status page. Several strategies for working around this constraint are presented below.
Conformance Rules for Random Access C++ Collections
The following two conditions must be satisfied in order for a C++ container
type to automatically conform to RandomAccessCollection
in Swift:
- The C++ container type must have
begin
andend
member functions. Both functions must be constant and must return the same iterator type. - The C++ iterator type must satisfy the
RandomAccessIterator
C++ requirement. It must be possible to advance it usingoperator +=
in C++ and also to subscript into it usingoperator []
in C++. - The C++ iterator type must be comparable using
operator ==
. Swift currently doesn’t support templatedoperator ==
, so it must operate on the concrete iterator type used by the container.
When these conditions are satisfied, Swift conforms the Swift structure
that represents the underlying C++ container type to
the CxxRandomAccessCollection
protocol, which adds the
RandomAccessCollection
conformance.
C++ Containers Can Be Converted to Swift Collections
The sequential C++ container types that do not provide random access to their
elements are automatically
conformed to the CxxConvertibleToCollection
protocol in Swift.
For example, the std::set
container returned by this
function is conformed to the CxxConvertibleToCollection
protocol
automatically by Swift:
std::set<int> getWinningNumers();
The conformance to CxxConvertibleToCollection
makes it possible
to easily convert a C++ container to a Swift collection type, like
Array
or Set
. For example, the std::set
returned
by getWinningNumers
can be converted to both a Swift Array
and
a Swift Set
:
let winners = getWinningNumers()
for number in Array(winners) {
print(number)
}
let setOfWinners = Set(winners)
C++ containers that automatically conform to the CxxRandomAccessCollection
protocol also automatically conform to the CxxConvertibleToCollection
protocol.
Conformance Rules for CxxConvertibleToCollection
Protocol
The following two conditions must be satisfied
in order for a C++ container type to automatically conform to
CxxConvertibleToCollection
in Swift:
- The C++ container type must have
begin
andend
member functions. Both functions must be constant and must return the same iterator type. - The C++ iterator type must satisfy the
InputIterator
C++ requirement. It must be possible to increment it usingoperator ++
in C++ and also to dereference it usingoperator *
in C++. - The C++ iterator type must be comparable using
operator ==
. Swift currently doesn’t support templatedoperator ==
, so it must operate on the concrete iterator type used by the container.
Using Associative Container C++ Types in Swift
Associative C++ container types, like std::map
, provide efficient access
to stored elements using a lookup key.
The find
member function that performs such lookup is unsafe in Swift. Instead
of using find
, Swift automatically conforms associative containers from the
C++ standard library to the CxxDictionary
protocol. Such conformance lets
you use the subscript operator when working with an associative C++
container in Swift. For example, the std::unordered_map
returned by this
function is conformed to the CxxDictionary
protocol automatically by Swift:
std::unordered_map<std::string, std::string>
getAirportCodeToCityMappings();
The returned std::unordered_map
value can be used like a dictionary in Swift,
with the subscript returning
a value stored in the container, or nil
if such value doesn’t exist:
let mapping = getAirportCodeToCityMappings();
if let dubCity = mapping["DUB"] {
print(dubCity)
}
The provided subscript calls the container’s find
method safely inside of its
implementation.
Associative C++ containers can be converted to a Swift sequential collection
type like Array
, when you need to manually traverse through their elements
in Swift.
Swift does not conform custom associative C++ containers
to CxxDictionary
automatically. A manually written Swift extension
can be used to add the CxxDictionary
conformance
retroactively for a custom associative container type.
Recommended Approach for Using C++ Containers
The following summary outlines the current recommended approach for how to use C++ containers in Swift:
- Use
for-in
loop to traverse through a C++ container that conforms toRandomAccessCollection
. - Use collection APIs like
map
orfilter
when working with a C++ container that conforms toRandomAccessCollection
. - Use the subscript operator to access a specific element in a C++ container
that conforms to
RandomAccessCollection
- Convert other sequential containers to Swift collections if you’d
like to traverse through their elements, or if you’d like to
use collection APIs like
map
orfilter
. - Use the subscript operator from the
CxxDictionary
protocol when looking up values in an associative C++ container.
Using C++ Containers in Performance Sensitive Swift Code
Swift’s current for-in
loop makes a deep copy of the C++
container when traversing through its elements. You can avoid
this copy by using the forEach
method provided by the CxxConvertibleToCollection
protocol. For example, the std::vector<Tree>
container returned by
getEnchantedTrees
can be traversed using the forEach
method in Swift:
let trees = getEnchantedTrees()
// Swift should not copy the `trees` std::vector here.
trees.forEach { tree in
print(tree.kind)
}
Best Practices for Working with C++ Containers in Swift
Do Not Use C++ Iterators in Swift
As outlined at the start of this section, using C++ iterators is unsafe in Swift. It’s easy to misuse C++ iterators, for instance:
- it’s easy to use an iterator after the C++ container is destroyed.
- it’s easy to dereference an iterator that has advanced past the container’s last element.
You should use protocols like CxxRandomAccessCollection
,
CxxConvertibleToCollection
and CxxDictionary
when working with C++ containers
instead of relying on C++ iterator APIs.
Member functions inside of C++ container types that return C++ iterators are marked unsafe in Swift, just like member functions that return references. Other C++ APIs, like top-level functions that take or return iterators could still be directly available in Swift. You should avoid using such functions in Swift.
Borrow C++ Containers When Calling Swift Functions
C++ container types become value types in Swift. This means that
Swift calls the container’s copy constructor, which in turn copies all the
elements, every time a copy is made in Swift. For example,
Swift will copy all of the elements from a std::vector<int>
represented
by the CxxVectorOfInt
type into a new vector
whenever it’s passed into
this Swift function:
func takesVectorType(_ : CxxVectorOfInt) {
...
}
let vector = createCxxVectorOfInt()
takesVectorType(vector) // 'vector' is copied here.
Swift’s upcoming
parameter ownership modifiers,
which will be provided in an upcoming Swift release, will let you avoid copies
when passing immutable values to functions. Mutable values can be passed
by inout
to a Swift function, which lets you avoid a deep copy of
the C++ container:
func mutatesVectorType(_ : inout CxxVectorOfInt) {
...
}
var vector = createCxxVectorOfInt()
takesVectorType(&vector) // 'vector' is not copied!
Mapping C++ Types to Swift Reference Types
The Swift compiler allows you to annotate some C++ types and import them as reference types (or class
types) in Swift. Whether a C++ type should be imported as a reference type is a complex question, and there are two primary criteria that go into answering it.
The first criterion is whether object identity is part of the “value” of the type. Is comparing the address of two objects just asking whether they’re stored at the same location, or it is deciding whether they represent the “same object” in a more significant sense?
The second criterion whether objects of the C++ class are always passed around by reference. Are objects predominantly passed around using a pointer or reference type, such as a raw pointer (*
), C++ reference (&
or &&
), or a smart pointer (like std::unique_ptr
or std::shared_ptr
)? When passed by raw pointer or reference, is there an expectation that that memory is stable and will continue to stay valid, or are receivers expected to copy the object if they need to keep the value alive independently? If objects are generally allocated and remain at a stable address, even if that address is not semantically part of the “value” of an object, the class may be idiomatically a reference type. This will sometimes be a judgment call for the programmer.
The first and most important criteria is often not possible for a compiler to answer automatically by just looking at the code. If you want the Swift compiler to map a C++ type to a Swift reference type, you must annotate the C++ type with one of the following
customization macros from the <swift/bridging>
header:
Immortal Reference Types
Immortal reference types are not designed to be managed individually by the program. Objects of these types are allocated and then intentionally “leaked” without tracking their uses. Sometimes these objects are not truly immortal: for example, they may be arena-allocated, with an expectation that they will only be referenced from other objects within the arena. Nonetheless, they aren’t expected to be individually managed.
The only reasonable thing Swift can do with immortal reference types is import them as unmanaged classes. This is perfectly fine when objects are truly immortal. If the object is arena-allocated, this is unsafe, but it’s essentially an unavoidable level of unsafety given the choices of the C++ API.
To specify that a C++ type is an immortal reference type, apply the SWIFT_IMMORTAL_REFERENCE
attribute. Here’s an example of SWIFT_IMMORTAL_REFERENCE
being applied to the C++ type LoggerSingleton
:
class LoggerSingleton {
public:
LoggerSingleton(const LoggerSingleton &) = delete; // non-copyable
static LoggerSingleton &getInstance();
void log(int x);
} SWIFT_IMMORTAL_REFERENCE;
Now that LoggerSingleton
is imported as a reference type in Swift, the programmer will be able to use it in the following manner:
let logger = LoggerSingleton.getInstance()
logger.log(123)
Shared Reference Types
Shared reference types are reference-counted types that are passed around by pointer or reference in C++. They typically use either:
- custom retain and release operations that increment and decrement a reference count stored intrusively in the object.
- or, a non-intrusive shared pointer type like
std::shared_ptr
, that can store the reference count outside of the object.
Currently Swift can map C++ classes or structures that use custom retain
and release operations together with a reference count stored intrusively in the object
to a Swift reference type (that behaves like a Swift class
). Other types
that rely on std::shared_ptr
for reference counting can still be used
as value types in Swift.
To specify that a C++ type is a shared reference type, use the SWIFT_SHARED_REFERENCE
customization macro. This macro expects two arguments: a retain and release function. These functions must be global functions that take exactly one argument and return void. The argument must be a pointer to the C++ type (not a base type). Swift will call these custom retain and release functions where it would otherwise retain and release Swift classes. Here’s an example of SWIFT_SHARED_REFERENCE
being applied to the C++ type SharedObject
:
class SharedObject : IntrusiveReferenceCounted<SharedObject> {
public:
SharedObject(const SharedObject &) = delete; // non-copyable
static SharedObject* create();
void doSomething();
} SWIFT_SHARED_REFERENCE(retainSharedObject, releaseSharedObject);
void retainSharedObject(SharedObject *);
void releaseSharedObject(SharedObject *);
Now that SharedObject
is imported as a reference type in Swift, the programmer will be able to use it in the following manner:
let object = SharedObject.create()
object.doSomething()
// `object` will be released here.
Unsafe Reference Types
The SWIFT_UNSAFE_REFERENCE
annotation macro has the same effect as SWIFT_IMMORTAL_REFERENCE
annotation macro. However, it communicates different semantics: the type is intended to be used unsafely, rather than living for the duration of the program.
Unique Reference Types
Unique reference types, such as types passed around by std::unique_ptr
are
not yet supported by Swift.
Using C++ Standard Library from Swift
This section describes how to import the C++ standard library, and how to use the types provided by it in Swift.
Importing C++ Standard Library
Swift can import the platform’s C++ standard library, by importing
the CxxStdlib
module.
The std
namespace becomes std
enumeration in Swift. The functions and types
inside of the std
namespace become nested types and static functions in
the std
Swift enumeration.
The status page contains a list of the supported C++ standard libraries, that describes which C++ standard libraries are supported on the platforms supported by Swift.
Using std::string
The std::string
C++ type becomes a structure in Swift. It conforms to
the ExpressibleByStringLiteral
protocol, so it can be initialized directly
using a string literal in Swift:
import CxxStdlib
let s: std.string = "Hello C++ world!"
Swift String
can be easily converted to a C++ std::string
:
let swiftString = "This is " + "a Swift string"
let cxxString = std.string(swiftString)
The same conversion can be made in the opposite direction, going from a C++
std::string
to a Swift String
:
let cxxString = std.string("This is a C++ string")
let swiftString = String(cxxString)
Swift does not convert C++ std::string
type to Swift’s String
type
automatically.
Working with C++ References and View Types in Swift
As outlined
earlier,
member functions that return references, pointers, or certain structures/classes that
contain references or pointers are considered to be unsafe in Swift.
Such member functions often return references or view
types that point back inside of the this
object, or into memory owned by the
this
object. In such cases, the
lifetime of the object the returned reference or view points to is said to be dependent
on the lifetime
of its owning object (the this
object passed to the member function).
C++ currently doesn’t specify which member functions
return dependent references or views, and which member functions return
completely independent references or views.
Therefore
Swift assumes that any reference or any view
type returned by a member function is dependent on the this
object.
Dependent references and view types are unsafe in Swift, as the reference or view is not associated with its owning object. Thus the owning object can get destroyed while the reference is still in use. Because of this unsafety, and the assumption that all such references and views are dependent, Swift renames such member functions to emphasize their unsafety and to discourage their use in Swift.
This section describes the exact rules used by Swift to determine which member functions return dependent references or view types, and suggests approaches for how to write Swift wrappers that call such member functions safely from Swift. It also introduces two new customization macros that can be applied to C++ code to instruct Swift to treat some member functions it thinks are unsafe as safe instead.
C++ Types Considered to Be References or View Types by Swift
Swift assumes that a C++ member function that returns one of the following types is unsafe in Swift:
- C++ reference
- Raw pointer
- C++ class or structure without a user-defined copy constructor, that contains a field whose type is in this list, recursively.
For example, the following two C++ structures are view types in Swift’s eyes:
struct PairIntRefs {
int &firstValue;
const int &secondImmutableValue;
PairIntRefs(int &, const int &);
};
// Also a view type, since its `refs` field is a view type.
struct BagOfValues {
PairIntRefs refs;
int x;
BagOfValues(PairIntRefs, int);
};
The rules outlined above define a heuristic that Swift uses to detect member functions that likely return a dependent reference or view type. This heuristic doesn’t guarantee that all C++ member functions that return dependent references or views will be detected by Swift, and therefore some member functions that return dependent references or views could appear to be safe in Swift.
Safely Accessing References with Dependent Lifetime
The recommended approach to calling member functions that return a reference or a view type with a dependent lifetime is to wrap them in a Swift API that returns a copy of the referenced object.
For example, consider the Forest
class whose getRootTree
members
return references:
class Forest {
public:
const Tree &getRootTree() const { return rootTree; }
Tree &getRootTree() { return rootTree; }
...
private:
Tree rootTree;
};
As outlined earlier, both of these member
functions become __getRootTreeUnsafe
and __getRootTreeMutatingUnsafe
methods
in Swift. Such methods are not meant be called directly in your code. Instead,
you should write a wrapper that achieves the desired objective without
exposing the dependent reference, that can then be used throughout
your Swift codebase. For example, lets say you want to inspect the underlying
rootTree
value in Swift. You can add a wrapper that allows your Swift codebase
to inspect the rootTree
by extending the Forest
class in Swift
and adding a rootTree
computed property that returns a Tree
value:
import forestLib
extension Forest {
private borrowing func getRootTreeCopy() -> Tree {
return __getRootTreeUnsafe().pointee
}
var rootTree: Tree {
getRootTreeCopy()
}
}
The borrowing
ownership modifier used above is a
new addition
in Swift 5.9. Some development versions of Swift 5.9 might not allow you to
use borrowing
for copyable C++ types like Forest
. In such cases, prior
to the release of Swift 5.9, you can
use a mutating
method call chain instead to safely copy the Tree
returned
by getRootTree
instead:
import forestLib
extension Forest {
private mutating func getRootTreeCopy() -> Tree {
return __getRootTreeUnsafeMutating().pointee
}
var rootTree: Tree {
var mutCopy = self
return mutCopy.getRootTreeCopy()
}
}
Using Methods That Return References and Views with Independent Lifetime
Some C++ member functions that return a reference or a view type might
return a reference whose lifetime is independent from the this
object. Swift
will still assume that such member functions are unsafe. To change that, you can
annotate your C++ code to instruct Swift to either:
- Assume that a particular C++ member function returns a completely independent reference or view. Such member function is then assumed to be safe.
- Assume that a particular C++ class or structure is self contained. All member functions that return such self contained types are then assumed to be safe.
Annotating Methods Returning Independent References or Views
The SWIFT_RETURNS_INDEPENDENT_VALUE
customization macro from the
<swift/bridging>
header can be added to a C++ member functions, to let
Swift know that it doesn’t return a dependent reference or a
dependent view. Such member function is then assumed to be safe in Swift.
For example, the getName
member function in the NatureLibrary
C++ class
is a great candidate for SWIFT_RETURNS_INDEPENDENT_VALUE
, as its definition
clearly shows that it returns a pointer to a constant static string literal, that’s not
stored within the NatureLibrary
object itself:
class NatureLibrary {
public:
const char *getName() const SWIFT_RETURNS_INDEPENDENT_VALUE {
return "NatureLibrary";
}
};
Annotating C++ Structures or Classes as Self Contained
The SWIFT_SELF_CONTAINED
customization macro from the
<swift/bridging>
header can be added to a C++ structure or class, to let
Swift know that it’s not a view type. All member functions that return such self contained type are then assumed to be safe in Swift.
Accessing Swift APIs from C++
Swift compiler can generate a header file that contains C++ types and functions that represent the Swift types and functions defined in a Swift module. Such header file can then be included from C++ code, letting you use Swift types and call Swift functions from C++.
Swift considers all public types and functions defined in a Swift module as eligible to be exposed to C++ when generating the generated header file. However, not all public types and functions can be represented in C++ yet. The exact rules that determine which Swift types and functions currently get exposed to C++ in the generated header are described in the following status page section.
Using Swift Types and Functions from C++
A wide array of Swift types and functions gets exposed to C++. This section goes over the fundamentals of how the exposed Swift types and functions can be used from C++.
Calling Swift Functions
Top-level Swift functions that are exposed to C++ become inline
C++ functions
in the generated header. The C++ functions are placed in the C++ namespace
that represents the Swift module. The body of such C++ function calls the native
Swift function directly from C++, without using any kind of indirection.
For example, the following Swift function gets exposed to C++ in the generated header:
// Swift module 'Greeter'
public func printWelcomeMessage(_ name: String) {
print("Welcome \(name)")
}
C++ code can call printWelcomeMessage
after including the generated
header:
#include <Greeter-Swift.h>
void cPlusPlusCallsSwift() {
Greeter::printWelcomeMessage("Theo");
}
Using Swift Structures In C++
Swift structures that are exposed to C++ become final C++ classes in the
generated header. Top-level structures are placed in the C++ namespace
that represents the Swift module. The exposed initializers, methods and
properties defined inside of the Swift structure become members of the
C++ class.
The C++ class that represents a Swift structure is copyable. Its copy constructor copies the underlying Swift value into a new value. The destructor of the C++ class destroys the underlying Swift value.
Currently C++ classes that represent Swift structures cannot be moved
in C++ using std::move
.
Creating a Swift Structure in C++
The exposed initializers of a Swift structure become static init
member
functions in the C++ class. The C++ code can then call one of such functions
to create an instance of the structure in C++.
For example, Swift exposes the MountainPeak
structure shown below in the
generated header:
// Swift module 'Landscape'
public struct MountainPeak {
let name: String
let height: Float
public init(name: String, height: Float) {
self.name = name
self.height = height
}
}
The init
static member function from the MountainPeak
C++ class can
be used to create a MountainPeak
instance in C++:
#include <Landscape-Swift.h>
using namespace Landscape;
void createMountainRange() {
auto tallestMountain = MountainPeak::init("Everest", 8848.9);
}
Using Swift Classes in C++
Swift classes that are exposed to C++ become C++ classes in the
generated header. Top-level classes are placed in the C++ namespace
that represents the Swift module. The exposed initializers, methods and
properties defined inside of the Swift structure become members of the
C++ class.
The C++ class that represents a Swift class is copyable and movable. Its copy and move constructors, and its destructor obey the rules of Swift’s automatic reference counting (ARC) model that allows the program to release the Swift class instance when it’s no longer referenced.
For example, Swift exposes the MountainRange
class shown below in the
generated header:
// Swift module 'Landscape'
public class MountainRange {
let peaks: [MountainPeak]
public init(peaks: [MountainPeak]) {
self.peaks = peaks
}
}
public func createSierras() -> MountainRange {
...
}
public func render(mountainRange: MountainRange) {
...
}
A MountainRange
instance can then be passed around in C++ safely. ARC
will release it once it’s no longer in use:
#include <Landscape-Swift.h>
using namespace Landscape;
void renderSierras() {
MountainRange range = createSierras();
render(range);
// The `MountainRange` instance that `range` points to is freed by ARC when
// this C++ function returns.
}
The inheritance hierarchy of Swift classes is represented using a C++ inheritance hierarchy formed by the C++ classes that represent the exposed Swift classes.
Using Swift Enumerations in C++
Swift enumerations that are exposed to C++ become C++ classes in the
generated header. Top-level enumerations are placed in the C++ namespace
that represents the Swift module. The exposed initializers, methods and
properties defined inside of the Swift enumeration become members of the
C++ class.
The C++ class that represents a Swift enumeration is copyable. Its copy
constructor copies the underlying Swift value into a new value. The destructor
of the C++ class destroys the underlying Swift value. Currently C++
classes that represent Swift enumerations cannot be moved in C++ using
std::move
.
The enumeration cases become static inline
constant C++ data members in the
C++ class that represents the enum. These members let you:
- Construct a Swift enumeration that is set to the specific case value in C++.
- Switch over a Swift enumeration using a
switch
statement in C++.
For example, the following Swift enumeration is exposed in the generated header:
// Swift module 'Landscape'
public enum VolcanoStatus {
case dormant
case active
}
A VolcanoStatus
instance can be constructed from C++, by using
operator()
on one of its members that represents an enumeration case.
You can also reference such member in the case
condition inside of a
switch
statement in C++:
#include <Landscape-Swift.h>
using namespace Landscape;
VolcanoStatus invertVolcanoStatus(VolcanoStatus status) {
switch (status) {
case VolcanoStatus::dormant:
return VolcanoStatus::active(); // Returns `VolcanoStatus.active` case.
case VolcanoStatus::active:
return VolcanoStatus::dormant(); // Returns `VolcanoStatus.dormant` case.
}
}
The unknownDefault
C++ member allows you to write an exhaustive C++ switch
for a resilient Swift enumeration, as such enumeration might get more cases in
the future that the C++ code does not know about.
Using Enumerations with Associated Values
Swift allows an enumeration to associate a set of values with a particular case. Enumerations whose cases have one associated value, or no associated values, get exposed to C++. They become C++ classes in the generated header. The interface of such C++ class closely resembles the interface of a class generated for a Swift enumeration without associated values. Such classes also contain additional getter member functions, that let you extract the associated value stored in the enumeration once you determine which case the enumeration is set to.
For example, the following Swift enumeration with associated values is exposed in the generated header:
// Swift module 'Landscape'
public enum LandmarkIdentifier {
case name(String)
case id(Int)
}
The value associated with one of the cases of LandmarkIdentifier
can be
extracted by calling the appropriate getter method in C++:
#include <Landscape-Swift.h>
#include <iostream>
using namespace Landscape;
void printLandmarkIdentifier(LandmarkIdentifier identifier) {
switch (status) {
case LandmarkIdentifier::name:
std::cout << (std::string)identifier.getName();
break;
case LandmarkIdentifier::id:
std::cout << "unnamed landmark #" << identifier.getId();
break;
}
}
A new LandmarkIdentifier
instance can be constructed from C++ as well:
auto newLandmarkId = LandmarkIdentifier::id(1234);
Calling Swift Methods
Swift methods become member functions in C++.
Swift structures and enumerations have mutating
and nonmutating
methods.
Nonmutating
methods become constant member functions in C++.
Accessing Swift Properties in C++
Both stored and computed properties become getter and setter member functions in C++. The getter is a constant member function that returns the value of the Swift property. Mutable properties have a setter in C++ as well. The setter is a member function and should not be invoked on immutable instances of a Swift value type.
For example, the following Swift structure is exposed to C++ in the generated header:
public struct LandmarkLocation {
public var latitude: Float
public var longitude: Float
}
C++ code can then call getLatitude
and getLongitude
member functions
to access the stored property values.
Using Swift Standard Library Types from C++
Several Swift standard library types can be used in C++. This section describes how to use the supported Swift standard library types in C++.
Using Swift String
in C++
Swift’s String
type is exposed to C++. It can be initialized directly
using a string literal in C++:
#include <SwiftLibrary-Swift.h>
void createSwiftString() {
swift::String test = "Hello Swift world!";
}
A C++ std::string
can be easily converted to a Swift String
:
void callSwiftAPI(const std::string &stringValue) {
SwiftLibrary::functionTakesString(swift::String(stringValue));
}
The same conversion can be made in the opposite direction, going from a
Swift String
to a C++ std::string
:
std::string getStringFromSwift() {
return (std::string)SwiftLibrary::giveMeASwiftString();
}
The C++ representation of String
provides access to a number of
String’s methods and properties including:
isEmpty
getCount
lowercased
anduppercased
hasPrefix
andhasSuffix
append
Several other methods and properties not listed here are also available.
An Objective-C NSString *
can be
converted to and from a Swift String
in Objective-C++ language mode.
Using Swift Array
in C++
Swift’s Array
type is exposed to C++. C++ represents it using the
swift::Array
class template. It must be instantiated with a C++ type that
represents a Swift type. It can also be instantiated with a native C++ type,
when a Swift Array
of such type is used in Swift and is exposed back to C++
via a public Swift API.
A Swift Array
can be traversed using a for
loop in C++. For example,
take the StringsAndNumbers
Swift module interface:
// Swift module 'StringsAndNumbers'
public func findTheStrings() -> [String]
public func processRandomNumbers(_ numbers: [Float])
A C++ for
loop can traverse over the Array
returned
from findTheStrings
:
#include <StringsAndNumbers-Swift.h>
void printTheFoundStrings() {
auto stringsArray = StringsAndNumbers::findTheStrings();
for (const auto &swiftString: stringsArray) {
std::cout << (std::string)swiftString << ", ";
}
}
An empty Array
can be created in C++, mutated, and then passed to Swift.
For example, C++ code can create an Array
that contains some floating point
numbers and pass it to processRandomNumbers
:
#include <StringsAndNumbers-Swift.h>
void processSomeTrulyUniqueRandomNumbers() {
auto array = swift::Array<float>::init();
array.append(1.0f);
array.append(42.0f);
StringsAndNumbers::processRandomNumbers(array);
}
Individual elements in the array can be accessed using operator []
in C++.
You cannot mutate an array element using operator []
however. C++ does not
yet support mutating individual elements in a Swift Array
.
The C++ representation of Array
provides access to a number of
Array’s methods and properties including:
getCount
getCapacity
append
insertAt
removeAt
Several other methods and properties not listed here are also available.
Using Swift Optional
in C++
Swift’s Optional
type is exposed to C++. C++ represents it using the
swift::Optional
class template. It must be instantiated with a C++ type that
represents a Swift type. It can also be instantiated with a native C++ type,
when a Swift Array
of such type is used in Swift and is exposed back to C++
via a public Swift API.
A value stored in a Swift Optional
can be extracted using the get
member
function. For example,
take the OptionalValues
Swift module interface:
// Swift module 'OptionalValues'
public func maybeMakeString() -> String?
public func callMeOnThePhoneMaybe(_ number: UInt64?)
The C++ get
member function can be used to extract the String
value returned by maybeMakeString
:
#include <OptionalValues-Swift.h>
void printAStringOrNone() {
auto maybeString = OptionalValues::maybeMakeString();
if (maybeString) {
std::cout << (std::string)maybeString.get() << "\n";
} else {
std::cout << "Got no value from Swift :( \n";
}
}
The Optional
is implicitly convertible to bool
in C++. That allows
you to check if it has a value in an if
condition, like in the example
shown above.
A Swift Optional
can also be constructed from C++, using the
some
or none
case constructor:
#include <OptionalValues-Swift.h>
void callMeOnThePhone() {
OptionalValues::callMeOnThePhoneMaybe(
swift::Optional<uint64_t>::some(1234567890));
}
Appendix
This section contains additional tables and references for certain topics that are outlined in the documentation above.
List of Customization Macros in <swift/bridging>
Macro | Documentation |
---|---|
SWIFT_NAME |
Renaming C++ APIs in Swift |
SWIFT_COMPUTED_PROPERTY |
Mapping Getters and Setters to Computed Properties |
SWIFT_CONFORMS_TO |
Conforming Class Template to Swift Protocol |
SWIFT_IMMORTAL_REFERENCE |
Immortal Reference Types |
SWIFT_SHARED_REFERENCE |
Shared Reference Types |
SWIFT_UNSAFE_REFERENCE |
Unsafe Reference Types |
SWIFT_RETURNS_INDEPENDENT_VALUE |
Annotating Methods Returning Independent References or Views |
SWIFT_SELF_CONTAINED |
Annotating C++ Structures or Classes as Self Contained |
Document Revision History
This section lists the recent changes made to this reference guide.
2023-06-05
- Published the initial version of the guide that describes how to mix Swift and C++.