You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/CppInteroperability/UserGuide-CallingSwiftFromC++.md
+83-24Lines changed: 83 additions & 24 deletions
Original file line number
Diff line number
Diff line change
@@ -2,7 +2,10 @@
2
2
3
3
A Swift library author might want to expose their interface to C++, to allow a C++ codebase to interoperate with the Swift library. This document describes how this can be accomplished, by first describing how Swift can expose its interface to C++, and then going into the details on how to use Swift APIs from C++.
4
4
5
-
**NOTE:** This is a work-in-progress, living guide document for how Swift APIs can be imported and used from C++.
5
+
6
+
**NOTE:** This is a work-in-progress, living guide document for how Swift APIs can be imported and used from C++. This document reflects the current state of the experimental design, and it will evolve over time
7
+
as this feature will go through Swift's evolution process. This document does not specify the final target
8
+
design for the Swift to C++ interoperability layer.
6
9
7
10
**NOTE:** This document does not go over the following Swift language features yet:
8
11
@@ -71,7 +74,7 @@ Fundamental primitive types have a C++ fundamental type that represents them in
71
74
|--- |--- |--- |--- |--- |
72
75
|Void (or no return) |void ||||
73
76
|Int |swift::Int |ptrdiff_t |long or long long (windows) |YES |
74
-
|UInt |size_t||unsigned long or unsigned long long (windows) |YES |
77
+
|UInt |swift::UInt|size_t|unsigned long or unsigned long long (windows) |YES |
75
78
|Float |float ||||
76
79
|Double |double ||||
77
80
||||||
@@ -424,7 +427,7 @@ int main() {
424
427
425
428
## Using Swift Enumeration Types
426
429
427
-
A Swift enumeration is imported as class in C++. That allows C++ to invoke methods and access properties that the enumeration provides. Each enumeration case that doesn’t have associated value is exposed as a static variable in the structure.
430
+
A Swift enumeration is imported as class in C++. That allows C++ to invoke methods and access properties that the enumeration provides. Each enumeration case is represented by a static variable that can be used in a switch to match the case of the enum, and to construct new enums values as well.
428
431
429
432
For example, given the following enum:
430
433
@@ -444,32 +447,44 @@ The following interface will be generated:
444
447
// "Navigation-Swift.h" - C++ interface for Swift's Navigation module.
445
448
classCompassDirection {
446
449
public:
447
-
static const CompassDirection north;
448
-
static const CompassDirection south;
449
-
static const CompassDirection east;
450
-
static const CompassDirection west;
450
+
static const struct { ... } north;
451
+
static const struct { ... } south;
452
+
static const struct { ... } east;
453
+
static const struct { ... } west;
454
+
private:
455
+
// type representation details.
456
+
...
451
457
};
452
458
```
453
459
460
+
This will let you construct enumeration values from C++ using the C++ call operator on the case:
461
+
462
+
```c++
463
+
#include "Navigation-Swift.h"
464
+
465
+
void testConstructEnumValue() {
466
+
auto direction = CompassDirection::north();
467
+
}
468
+
```
469
+
454
470
### Matching Swift Enumeration Values with a C++ Switch Statement
455
471
456
-
Swift’s enumerations can not be used directly in a switch, as C++ does not allow a `switch` to operate on C++ classes. However, For Swift enumerations that have an underlying integer representation, the generated C++ interface provides a convenience C++ enum called `cases` inside of the generated C++ class that represents the enumeration. This C++ enum can then be used in a switch, as the class that represents the enumeration implicitly converts to it. The `cases` C++ enum allows us to switch over the `CompassDirection` class from the example above in the following manner:
472
+
The C++ values that correspond to Swift enumeration case values can be used directly inside the switch statement. The generated C++ interface provides a convenience C++ enum called cases inside of the generated C++ class that represents the enumeration that the switch actually operates over. This C++ enum can then be used in a switch, as the class that represents the enumeration implicitly converts to it, and so do the C++ case values. This allows us to switch over the CompassDirection class from the example above in the following manner:
The C++ user of this enumeration can then use it by checking the type of the value and getting the associated value using the `is` and `get` member functions:
571
+
The C++ user of this enumeration can then use it by checking the type of the value in a switch and getting the associated value using the get member functions:
The use of a `get` associated value accessor for an invalid enum case for the given
591
+
enum value will abort the program.
592
+
593
+
### Resilient Enums
594
+
595
+
A resilient Swift enumeration value could represent a case that's unknown to the client.
596
+
Swift forces the client to check if the value is `@uknown default` when switching over
597
+
the enumeration to account for that. C++ follows a similar principle,
598
+
by exposing an `unknown_default` case that can then be matched in a switch.
599
+
600
+
For example, given the following resilient enumeration:
601
+
602
+
```swift
603
+
// Swift module 'DateTime'
604
+
enumDateFormatStyle {
605
+
casemedium
606
+
casefull
607
+
}
608
+
```
609
+
610
+
In C++, you need do an exhaustive switch over all cases and the unknown default
611
+
case to avoid any compiler warnings:
612
+
613
+
```c++
614
+
usingnamespaceDateTime;
615
+
voidtest(const DateFormatStyle &style) {
616
+
switch (style) {
617
+
case DateFormatStyle::medium:
618
+
...
619
+
break;
620
+
case DateFormatStyle::full:
621
+
...
622
+
break;
623
+
case DateFormatStyle::unknown_default: // just like Swift's @unknown default
624
+
// Some case value added in a future version of enum.
625
+
break;
626
+
}
570
627
}
571
628
```
572
629
630
+
The `unknown_default` case value is not a constructible case and you will get a compiler error if you try to construct it in C++.
631
+
573
632
## Using Swift Class Types
574
633
575
634
Swift class types that are usable from C++ are available in their corresponding module namespace. They’re bridged over as a C++ class that stores a referenced counted pointer inside of it. Its initializers, methods and properties are exposed as members of the C++ class.
0 commit comments