In a pure C++ world we can generate interfacing or glue code between different components or interfaces at compile time, using a combination of template-based compile-time and runtime-techniques (to e.g. mostly automatically marshall to/from calls using legacy types).
When having to interface C++ applications with Objective-C/Cocoa for GUI, system integration or IPC though, things become harder due to the less strict typing - yet often not more then a flat repitive interface layer is needed: thin bridging delegates have to be defined or conversion code to language bridging calls has to be written.
If you have to deal with interfaces of non-trivial size and want to avoid script-based code generation this quickly becomes cumbersome and is just a pain every time refactorings have to take place. Using a combination of (template) metaprogramming and the Objective-C runtime library, it should be possible to reduce the amount of code considerably...
Before i go to reinvent the wheel (and possibly waste time), does anyone know about techniques, best-practices or examples in that direction?
As for an example, lets say we need a delegate that supports this informal protocol:
- (NSString*)concatString:(NSString*)s1 withString:(NSString*)s2; - (NSNumber*) indexOf:(CustomClass*)obj;
Instead of implementing an Obj-C class now that explicitly bridges to a C++-instance, i'd like to do something like this instead:
class CppObj { ObjcDelegate m_del; public: CppObj() : m_del(this) { m_del.addHandler <NSString* (NSString*, NSString*)> ("concatString", &CppObj::concat); m_del.addHandler <NSNumber* (CustomClass*)> ("indexOf", &CppObj::indexOf); } std::string concat(const std::string& s1, const std::string& s2) { return s1.append(s2); } size_t indexOf(const ConvertedCustomClass& obj) { return 42; } };
All that should be needed from the user to support additional types would be to specialize a conversion template function:
template<class To, class From> To convert(const From&); template<> NSString* convert<NSString*, std::string>(const std::string& s) { // ... } // ...
The example above of course does ignore support for formal protocols etc. but should get the point across. Also, due to the type-information for Objc-runtime-types being mostly decayed into some-native-types or class-type i don't think the explicit specification of parameter and return types for the delegate-methods can be avoided.
I didn't find anything satisfactory and came up with a prototype that, given the following informal protocol:
- (NSString*)concatString:(NSString*)s1 withString:(NSString*)s2;
and this C++ code:
struct CppClass { std::string concatStrings(const std::string& s1, const std::string& s2) const { return s1+s2; } }; std::string concatStrings(const std::string& s1, const std::string& s2) { return s1+s2; }
allows creating and passing a delegate:
CppClass cpp; og::ObjcClass objc("MyGlueClass"); objc.add_handler<NSString* (NSString*, NSString*)> ("concatString:withString:", &cpp, &CppClass::concatStrings); // or using a free function: objc.add_handler<NSString* (NSString*, NSString*)> ("concatString:withString:", &concatStrings); [someInstance setDelegate:objc.get_instance()];
which can then be used:
NSString* result = [delegate concatString:@"abc" withString:@"def"]; assert([result compare:@"abcdef"] == NSOrderedSame);
Boost.Function objects can also be passed, which means Boost.Bind can easily be used as well.
While the basic idea works, this is still a prototype. I did a short blog post on the subject and the prototype source is available via bitbucket. Constructive input and ideas welcome.
Did you look at the wxWidgets library? I don't code in Objective-C, but at least the developers claim decent support for Cocoa/Objective-C. Which means, they have some mapping from C++ implemented somehow. The library's website is http://www.wxwidgets.org.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With