通过元编程简化c ++到objective-c/cocoa桥接?

Geo*_*che 34 c++ cocoa metaprogramming objective-c

在纯C++世界中,我们可以在编译时使用基于模板的编译时和运行时技术的组合在不同组件或接口之间生成接口或粘合代码(例如,大多数自动编组到使用传统类型的调用).

当必须使用Objective-C/Cocoa将C++应用程序与GUI,系统集成或IPC接口时,由于不太严格的类型,事情变得更加困难 - 但通常不需要更多的平面复制接口层:瘦桥接代表必须是必须编写定义或转换代码到语言桥接调用.

如果你必须处理非平凡大小的接口并希望避免基于脚本的代码生成,这很快变得麻烦,并且每次重构都必须发生时只是痛苦.使用(模板)元编程和Objective-C运行时库的组合,应该可以大大减少代码量...

在我重新发明轮子之前(可能浪费时间),有没有人知道这方面的技术,最佳实践或例子?


举个例子,假设我们需要一个支持这种非正式协议的委托:

- (NSString*)concatString:(NSString*)s1 withString:(NSString*)s2;
- (NSNumber*)     indexOf:(CustomClass*)obj;
Run Code Online (Sandbox Code Playgroud)

现在,我没有实现明确桥接到C++实例的Obj-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;
    }
};
Run Code Online (Sandbox Code Playgroud)

用户需要支持其他类型的所有内容都是专门化转换模板功能:

template<class To, class From> To convert(const From&);

template<> 
NSString* convert<NSString*, std::string>(const std::string& s) { 
    // ...
}

// ...
Run Code Online (Sandbox Code Playgroud)

上面的例子当然会忽略对正式协议等的支持,但应该明白这一点.此外,由于Objc-runtime-types的类型信息主要被衰减为某些本机类型或类类型,我不认为可以避免委托方法的参数和返回类型的显式规范.

Geo*_*che 5

我没有找到任何令人满意的东西,并提出了一个原型,给出了以下非正式协议:

- (NSString*)concatString:(NSString*)s1 withString:(NSString*)s2;
Run Code Online (Sandbox Code Playgroud)

这个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;
}
Run Code Online (Sandbox Code Playgroud)

允许创建和传递委托:

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()];
Run Code Online (Sandbox Code Playgroud)

然后可以使用:

NSString* result = [delegate concatString:@"abc" withString:@"def"];
assert([result compare:@"abcdef"] == NSOrderedSame);
Run Code Online (Sandbox Code Playgroud)

Boost.Function对象也可以传递,这意味着Boost.Bind也可以轻松使用.

虽然基本思想有效,但这仍然是一个原型.我做了一篇关于这个主题的简短博客文章,原型来源可以通过bitbucket获得.建设性的意见和想法欢迎.