通过元编程缓解c ++到目标c /可可桥接? [英] easing c++ to objective-c/cocoa bridging via metaprogramming?
问题描述
当使用Objective-C / Cocoa for GUI,系统集成或IPC接口C ++应用程序时,由于不太严格的类型,事情变得更难,那么需要一个平面的回复接口层:必须定义薄桥接委托,或者必须写入转换代码到语言桥接调用。
如果你必须处理非平凡大小的接口,并希望避免基于脚本的代码生成,这会很快变得繁琐,每次重构时发生。使用(模板)元编程和Objective-C运行时库的组合,应该可以大大减少代码量。
在我去重构之前(可能浪费时间),有没有人知道这方面的技术,最佳实践或示例?
例如,我们需要一个支持这个非正式协议的委托:
- NSString *)concatString:(NSString *)s1 withString:(NSString *)s2;
- (NSNumber *)indexOf:(CustomClass *)obj;
而不是实现一个Obj-C类现在明确桥接到一个C ++实例,像这样:
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;
}
};
用户需要支持其他类型的所有功能将是转换模板功能:
模板< class To,class From>转换(const From&);
模板<>
NSString * convert< NSString *,std :: string>(const std :: string& s){
// ...
}
...
上面的例子当然忽略对正式协议等的支持,跨越。此外,由于Objc运行时类型的类型信息主要是衰变到一些本地类型或类类型我不认为显式规范的参数和返回类型的代理 - 可以避免方法。
我没有发现什么令人满意的,并提出了一个原型,协议:
- (NSString *)concatString:(NSString *)s1 withString:(NSString *)s2;
和此C ++代码:
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;
}
允许创建和传递委托:
CppClass cpp;
og :: ObjcClass objc(MyGlueClass);
objc.add_handler< NSString *(NSString *,NSString *)>
(concatString:withString:,& cpp,& CppClass :: concatStrings);
//或使用自由函数:
objc.add_handler< NSString *(NSString *,NSString *)>
(concatString:withString:,& concatStrings);
[someInstance setDelegate:objc.get_instance()];
可以使用:
NSString * result = [delegate concatString:@abcwithString:@def];
assert([result compare:@abcdef] == NSOrderedSame);
Boost.Function 对象也可以传递,
虽然基本思想是有效的,但这仍然是一个原型。我对该主题做了一个简短的博客文章,并提供了原型来源 via bitbucket 。建设性的意见和想法欢迎。
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.
这篇关于通过元编程缓解c ++到目标c /可可桥接?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!