views:

178

answers:

3

I have a C++ library (.h only) that contains the implementation of a data structure and I'd like to use it in my iPhone app.

Firstly, I wrote a wrapper in objective-C++ as a class that, through composition, has an ivar of the C++ class. I then was 'obliged' to change the wrapper class extension to .mm, and it seemed fine. But then I have to include this wrapped class file into several other files, so I have to change their extension too (in order to prevent a wave of compile-time errors).

Am I correct? Is there a way to 'confine' the .mm extension to just few files?(and so preventing name clashes etc)

EDIT: Some more info that might help, I'm using LLVM 1.5 as the compiler (I noticed that the number of compile time errors varies from GCC 4.2 to LLVM 1.5 but I'm not sure that it means much, since I didn't have a look at them all)

+2  A: 

I'm not sure I understand your question fully, but I think the answer is 'Yes'.

Basically anything that needs to refer to the wrapper class is Objective-C++ code, not straight C++.

I suggest that you confine your inclusion of the wrapper class to implementation (aka .cpp or the Objective-C++ equivalent) files. They should not cause the header file describing the classes they implement to become Objective-C++.

Techniques like the Pimpl idiom can help isolate users of your class from the fact that it's implemented partly in Objective-C++.

Omnifarious
+1 I got your point in limiting the cascade by including just in the `.mm` files
rano
@rano - It looks like your problem is the reverse problem of the one I described the solution to. And it looks like Objective-C/C++ doesn't have the concept of an implementation as separate from the class definition. This makes the job a lot harder and requires a greater understanding than I have of Objective-C/C++.
Omnifarious
@Omnifarious: I'm not getting your point now, objective-C/C++ provides separation for the interface/implementation of a class
rano
@rano - *sigh* Oops. I think I need to learn a lot more about Objective-C++ than the smattering of stuff I know to help you better. The Pimpl idiom relies on there being a separation between the definition and implementation of the class to work. So if Objective-C++ allows this, then it's possible to translate it over into that language.
Omnifarious
+4  A: 

My recommendation is to wrap the C++ bits in #ifdefs:

//MyWrapper.h

#ifdef __cplusplus
class ComposedClass;
#endif 

@interface MyWrapper : NSObject
{
#ifdef __cplusplus
ComposedClass *ptr;
#endif
}

// wrapped methods here...
@end

This is a slightly lame version of the PIMPL idiom, but less code, and effective for hiding C++-isms from your pure Objective-C code. Obvioulsy you would have to include the ComposedClass's header in your MyWrapper.mm.

If ComposedClass is a templated type, you will need to modify the first block to

#ifdef __cplusplus
#include "ComposedClass.h"
#endif

instead of using a forward declaration and then, of course, use the templated type in your Objective-C class' instance variable declaration.

This approach was suggested by Greg Parker, the runtime guru at Apple.

Barry Wark
I don't think that's a good idea. Any non-C++ files that include this header would not "see" the protected members, and so will have different sizes for classes and different offsets for instance variables.
Kristopher Johnson
@Kristopher, using modern Objective-C runtime (which is the only option on iOS), instance variables are non-fragile, and this isn't a problem.
Barry Wark
@Barry Wark ty Barry this seems the easiest way to me but it appears I'm not able to achieve this since I get compile-time errors http://pastebin.com/tp9Zjhss seems like I'm missing something, I thought they could be templates but in your link they are used.
rano
@rano, Sorry...I missed the header-only. In that case, I would include the RTree header in your Wrapper .h (still #ifdef'd for __cplusplus only).
Barry Wark
@Barry Wark: thank you for answering I already tried it and even though there are no more compile time errors in my wrapper.h there are some new ones in the .mm file since when I use the ivar it says `invalid use of incomplete type ...templateClassName...`. By looking for this on the web I noticed that it might mean the template has not been instantiated yet. Any suggestion?
rano
@rano, my C++ foo is weak. I didn't notice in your pastebin posting that you didn't #include the header before the forward declaration. I've modified my answer, and that may do it for you. Otherwise, you can always explicitly instantiate a template in your `.mm` file, e.g. `template class RTree< void *, double, 2, double >;`.
Barry Wark
@Brad Wark: the template instantiation was the key (this shows my C++ is weaker than yours : D), thank you (including the header ifdef'd alone was not enough)
rano
+3  A: 

Any code that includes a C++ snippet (no matter how small) must be compiled with Objective-C++ (and hence be in a .mm file). If you want to narrow down the number of .mm files, you would have to wrap the functionality of your C++ code in an Objective-C class so that this class's public interface (its .h file) only consists of Objective-C code. That means the wrapper class must not contain a public ivar of a C++ type. Whether this is a feasible approach if your C++ lib only consists of a data structure, I don't know.

Note that AFAIK LLVM 1.5 does not include C++ support yet (only LLVM 2.0 does). AFAIK, when you select LLVM 1.5, Xcode will automatically switch to GCC for all C++/Objective-C++ files.

Ole Begemann
+1 for the compilers dilemma enlightenment : )
rano