Can I mix Swift with C++? Like the Objective-C .mm files

92,696

Solution 1

No. When you switch from .m to .mm you are actually switching from Objective-C to a different language (which has many subtle differences) called Objective-C++. So you're not really using C++; you're using Objective-C++ which accepts most C++ as input (in the same way that C++ accepts most but not all C as input). When I say it's not quite C++, consider a C++ file that includes a variable named nil (which is legal C++) and then try to compile that as Objective-C++.

Swift doesn't have the same relationship. It is not a superset of C or C++, and you can't directly use either in a .swift file.

"Using Swift with Cocoa and Objective-C" also tells us:

You cannot import C++ code directly into Swift. Instead, create an Objective-C or C wrapper for C++ code.

Solution 2

The confusion may come from the assumption that merely changing a file extension from .m to .mm is all you need to bridge the languages, when, in reality, it does nothing of that sort. It is not the .mm that causes friction with .cpp, it is the .h header which must positively not be a C++ header.


Same project: Yes.

In the same project, you can happily mix C, C++, Objective-C, Objective C++, Swift, and even Assembly.

  1. ...Bridging-Header.h: you expose C, Objective-C and Objective-C++ to Swift using this bridge
  2. <ProductModuleName>-Swift.h: exposes automatically your Swift classes marked with @objc to Objective-C
  3. .h: this is the tricky part, since they are ambiguously used for all flavors of C, ++ or not, Objective or not. When a .h does not contain a single C++ keyword, like class, it can be added to the ...Bridging-Header.h, and will expose whatever function the corresponding .c or .cpp functionalities it declares. Otherwise, that header must be wrapped in either a pure C or Objective-C API.

Same file: No.

In the same file, you can't mix all 5. In the same source file:

  1. .swift: you can't mix Swift with anything
  2. .m: you can mix Objective-C with C. (@Vinzzz)
  3. .mm: you can mix Objective-C with C++. This bridge is Objective-C++. (@Vinzzz).
  4. .c: pure C
  5. .cpp: you can mix C++ & Assembly (@Vality)
  6. .h: ubiquitous and ambiguous C, C++, Objective-C or Objective-C++, so the answer is it depends.

References

Solution 3

I wrote a simple Xcode 6 project that show how to mix C++, Objective C and Swift code:

https://github.com/romitagl/shared/tree/master/C-ObjC-Swift/Performance_Console

In particular the example call an Objective C and a C++ function from the Swift.

The key is to create a shared header Project-Bridging-Header.h and put the Objective C headers there.

Please download the project as a complete example.

Solution 4

You can also skip the Objective-C file in between. Just add a C header file with a .cpp source file. Have only C declarations in the header file and include any C++ code in the source file. Then include the C header file in the **-Bridging-Header.h.

The following example returns a pointer to a C++ object (struct Foo) so Swift can store in a COpaquePointer instead of having struct Foo defined in the global space.

Foo.h file (seen by Swift - included in the bridging file)

#ifndef FOO_H
#define FOO_H

// Strictly C code here.
// 'struct Foo' is opaque (the compiler has no info about it except that 
// it's a struct we store addresses (pointers) to it.
struct Foo* foo_create();
void foo_destroy(struct Foo* foo);

#endif

Inside source file Foo.cpp (not seen by Swift):

extern "C"
{
#include "Foo.h"
}
#include <vector>

using namespace std;

// C++ code is fine here. Can add methods, constructors, destructors, C++ data members, etc.
struct Foo
{
   vector<int> data;
};

struct Foo* foo_create()
{
   return new Foo;
}

void foo_destroy(struct Foo* foo)
{
    delete foo;
}

Solution 5

I have just made a little example project using Swift, Objective-C and C++. It's a demo of how to use OpenCV stitching in iOS. The OpenCV API is C++ so we can't talk to it directly from Swift. I use a small wrapper class who's implementation file is Objective-C++. The Header file is clean Objective-C, so Swift can talk to this directly. You have to take care not to indirectly import any C++-ish files into the the headers that Swift interacts with.

The project is here: https://github.com/foundry/OpenCVSwiftStitch

Share:
92,696
EhTd
Author by

EhTd

Updated on July 08, 2022

Comments

  • EhTd
    EhTd almost 2 years

    I just changed my .m files to .mm and use C++. Is there a way to do the same with Swift?

  • Morkrom
    Morkrom almost 10 years
    An intriguing nuance.
  • Jay
    Jay almost 10 years
    Pretty annoying actually - all of us with Cocoa apps incorporating C/C++ code bases now have to maintain projects written in 3 languages....
  • Jason Elwood
    Jason Elwood over 9 years
    Thanks for this Gian!
  • amar
    amar over 9 years
    I suggest that Objective-c++ is not a different language but a mix of c++ and Objective-c difference is subtle but its still there
  • rewolf
    rewolf over 9 years
    How is "nil" legal C++ ? There's no such thing (at least in standard c++) Please provide another example
  • rewolf
    rewolf over 9 years
    but from your answer it sounds like you can indeed call c++ from swift, provided there's a C-interface to those methods. If the OP is thinking like me, then he's hoping to share logic code between multiple platforms
  • Rob Napier
    Rob Napier over 9 years
    Yes, just as you can access C++ from ObjC if you give it a pure-C interface, you can also access C++ from Swift if you give it a pure-C interface.
  • chakrit
    chakrit over 9 years
    But with ObjC you can just go .mm your files and be (almost) done. Not so with Swift.
  • Alessandro Pirovano
    Alessandro Pirovano over 9 years
    Thanks you for this example, but if I want to move the #import "CPlusPlus.h" from ObjCtoCPlusPlus.mm to ObjCtoCPlusPlus.h file, the compiler return this error: <unknown>:0: error: failed to import bridging header '/Users/Ale/Downloads/shared-master/C-ObjC-Swift/Performance‌​_Console/Performance‌​_Console/Performance‌​_Console-Bridging-He‌​ader.h' it's possible move this import into header file?
  • Luke
    Luke over 9 years
    @rewolf, I think he means a variable named nil, like int nil
  • Rob Napier
    Rob Napier over 9 years
    I did, but in fairness it isn't really a great explanation. The same is true in C.
  • rewolf
    rewolf over 9 years
    gotcha! misunderstood :/ sorry :)
  • cacau
    cacau almost 9 years
    Ok - so what about Swift 2 and C++? :-)
  • Vinzzz
    Vinzzz over 8 years
    Correction : In the same .m source file, Objective-C being a strict C superset, you CAN mix Objective-C and C ...
  • Vinzzz
    Vinzzz over 8 years
    No problem, I don't even care for the credit, as long as the answer is the correct one ;) BTW, .mm is for mixing Objective-C and C++ (C and C++ are two different things, in spite of the name)
  • Vality
    Vality over 8 years
    I would mention that unlike objective C, C++ is not a C superset so you cannot mix both C and C++ in a .cpp file. Only C++ and assembly.
  • Slipp D. Thompson
    Slipp D. Thompson over 8 years
    @Jay: Not really. Wrappers can be auto-generated pretty easily, given a handful of procedures for method name/selector translation and type coversions. So after choices of Swift for your app, and C++ for the lib code you're using, that's zero additional languages you need to deal with on a day-to-basis / up to two additional (Obj-C, and some shell lang for running the auto-gens) you should know well enough to set up and maintain from time-to-time. That's assuming rolling your own though; it's possible that there's a good wrapper-auto-gen lib out there.
  • Slipp D. Thompson
    Slipp D. Thompson over 8 years
    @API: Nope, you're missing the point. ObjCtoCPlusPlus.h/``.mm` exists for the sole purpose of providing an Ob-C interface to C++ code— it is the bridge, which is a necessary component here. Leave the includes where they are, and add a method in the ObjCtoCPlusPlus.… files for each C++ method you need access to. You'd do well to read over sourcemaking.com/design_patterns/adapter
  • Jay
    Jay over 8 years
    @SlippD.Thompson Actually it's my own application code / core business logic that's written in C++ - can't afford the overhead of maintaining wrappers every time I'm changing anything in my code, which is like all the time as part of normal development process
  • Slipp D. Thompson
    Slipp D. Thompson over 8 years
    @Jay Sounds like auto-gen wrappers are the way to go then, since you understand both sides well.
  • Jay
    Jay over 8 years
    @SlippD.Thompson well.. still hoping for a more seamless solution somewhere down the road!
  • AeroBuffalo
    AeroBuffalo about 8 years
    In case anyone finds that this well detailed answer doesn't quite help when trying to expose Swift files into their Objective-C/C++ file (Xcode is complaining that the Swift header file is not found). I found that I had to import "ProductName/ProductModuleName-Swift.h" in my Objective-C/C++ source file. I found this somewhat buried at: developer.apple.com/library/ios/documentation/Swift/Conceptu‌​al/…
  • SwiftArchitect
    SwiftArchitect about 8 years
    Good point. For a working project mixing these languages, have a look at stackoverflow.com/a/32546879/218152.
  • rsp1984
    rsp1984 almost 8 years
    This answer deserves way more upvotes. Really useful.
  • enl8enmentnow
    enl8enmentnow over 7 years
    You are utterly confused because you do not understand your own answer. When a .h does not contain a single C++ keyword, like class, it can be added to the ...Bridging-Header.h -- that means it's a C file, not a C++ header, which is what Rob Napier said who, coincidentally, is not confused and has a clue.
  • Rocket Garden
    Rocket Garden about 7 years
    I think this answers a problem I hit today trying to use a 3rd party library KudanCV with Swift. My bridging header imports their .h file which contains imports to <memory> <strings> and <vectors> which I guess are from C++ libraries or files, as a result my Swift code will not compile. I'd be grateful if someone could tell me if there is a way around this... or if I have to rewrite all my code in Objective-C
  • foundry
    foundry about 7 years
    @RocketGarden - KudanCV header file is C++. You could write a wrapper that works in the same way as my example wrapper class. OR you rewrite those parts of your app that need to talk to KudanCV in objective-C++ (with a Objective-C headers). You wouldn't need to rewrite those parts of your project that are not concerned with KudanCV.
  • Rocket Garden
    Rocket Garden about 7 years
    Thanks for that, I realised it about 5 minutes later, but its useful to have it on record for others.
  • dcow
    dcow about 6 years
    This is the first time I've seen extern "C" wrap the header in the place it's included rather than #ifdef'ed in the header file itself. Brilliant!
  • leogdion
    leogdion over 5 years
    This is what I did. I wrote an article on how to integrate c++ with a swift project: learningswift.brightdigit.com/integrating-c-plus-plus-swift
  • Isaac
    Isaac almost 5 years
    I downloaded your example and it's fantastic for the STATIC function the class offers as an example, but I can't manage to adapt the example for an additional non-static function to be used from outside... Is it also possible? (I did my C++ homework decades ago... I'm not the sharpest pencil of the box right now)
  • kakyo
    kakyo almost 5 years
    Your sample code is in C not C++. Better go with an <iostream> example IMHO.
  • Sergei
    Sergei over 3 years
    Everyone one the internet: "you have to write objective-c wrapper for c++ classes". No you don't have to. Here is a simple trick to have one less language in you code base.