【问题标题】:easing c++ to objective-c/cocoa bridging via metaprogramming?通过元编程将 c++ 简化为objective-c/cocoa 桥接?
【发布时间】:2011-01-17 14:58:12
【问题描述】:

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

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

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

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


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

- (NSString*)concatString:(NSString*)s1 withString:(NSString*)s2;
- (NSNumber*)     indexOf:(CustomClass*)obj;

现在我不想实现一个显式桥接到 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;
    }
};

用户支持其他类型所需要的只是专门化一个转换模板函数:

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

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

// ...

上面的例子当然忽略了对正式协议等的支持,但应该明白这一点。此外,由于 Objc-runtime-types 的类型信息大多衰减为 some-native-types 或 class-type 我不认为代表的参数和返回类型的显式规范- 方法可以避免。

【问题讨论】:

  • 这是一个非常有趣的问题。我做了很多这种包装,虽然我使用了很多模式,但我从来没有真正找到一种元编程方法来简化模式。看看是否有人有会很有趣。 C++ 模板不能用于创建 ObjC 类,并且 C++ 缺乏足够的运行时自省来动态创建 ObjC 类。但是,某种模板语言可能是合适的;甚至可能基于宏。我目前正在为我在 Cocoaphany (robnapier.net) 上的下一篇文章研究这个主题,所以我必须多考虑一下。
  • 除非我忽略了某些东西,否则我至少可以使用 Obj-C 运行时修改和扩展 Objective-C 类(尚未研究类注册部分)。利用模板检查要绑定的 C++ 签名等。我在那个方向上没有看到大问题……至少现在还没有,这是我问的原因之一:)
  • 在我从事的项目中,我们使用以下方法:XML+外部代码生成器。我不知道这是否适合您,但无论如何......据我了解,这种方法一开始很痛苦,但是您不必每次都“重新发明”解决方案。你使用多少种语言并不重要。是的,在我们的例子中,XML 文件也被生成了:它可以通过 GUI 前端访问(当然你总是可以直接更改 XML)。
  • 我不喜欢外部代码生成,仅将其用作最后的手段。有趣的问题是如何使用元编程来尽可能避免对代码生成器的需求。我想当我的私人 Mac 到货时,我将不得不开始测试我的想法。
  • 这个问题很有趣+1,希望听到你的实验结果@gf。

标签: c++ objective-c cocoa metaprogramming


【解决方案1】:

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

- (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);
// or using a free function:
objc.add_handler<NSString* (NSString*, NSString*)>
    ("concatString:withString:", &concatStrings);
[someInstance setDelegate:objc.get_instance()];

然后可以使用:

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

Boost.Function 对象也可以被传递,这意味着 Boost.Bind 也可以很容易地使用。

虽然基本想法可行,但这仍然是一个原型。我在这个主题上做了一个简短的blog post,原型源可用via bitbucket。欢迎提出建设性意见和想法。

【讨论】:

    【解决方案2】:

    你看过 wxWidgets 库吗?我不在 Objective-C 中编写代码,但至少开发人员声称对 Cocoa/Objective-C 的支持不错。这意味着,他们以某种方式实现了一些来自 C++ 的映射。图书馆的网址是http://www.wxwidgets.org

    【讨论】:

    • 谢谢,似乎有一些通知桥接 - 稍后将不得不阅读更多内容。
    • 很好的提示,但不太令人满意。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-07
    相关资源
    最近更新 更多