是否可以将 C++0x lambda 转换为 clang 块?

发布于 2024-10-02 11:53:40 字数 418 浏览 9 评论 0原文

我想知道是否可以将 C++0x lambda 转换为 clang 块。到目前为止,我所看到的一切都涉及到他们之间差异的讨论。我研究这个的主要原因是为 libdispatch 制作一个最终的包装器,虽然我非常了解 dispatch_*_f 函数,但有关其使用的任何信息都有与他们的区块相比,这是相当缺乏的。

到目前为止,我已经能够找到有关 将 C++ lambda 转换为函数指针,但这更多的是相反的领域。

如果有人知道与此相关的任何信息,并且可以提供链接,或者至少为我指出正确的方向,我将非常感激。 (即使是“目前不可能”的答案就足够了)

I've wondered if it is possible to convert a C++0x lambda to a clang block. So far anything I've seen on it has involved the discussion between their differences. My primary reason for looking into this, is to make an eventual wrapper for libdispatch, and while I'm quite aware of dispatch_*_f functions, any information on their use has been quite lacking, in comparison to their block counterpart.

So far I've been able to find information on converting a C++ lambda to a function pointer, but this is more in the realm of the reverse.

If anyone knows anything related to this, and could provide a link, or at least point me in the right direction, I would really appreciate it. (even a "This is not currently possible" answer will suffice)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

云柯 2024-10-09 11:53:41

我建议使用 libdispatch 函数的 *_f 版本。所有的块版本都是根据底层的函数版本来实现的,编写一个生成调用 lambda 对象的函数的 C++ 模板比编写一个生成调用 lambda 的块的模板要容易得多一个 lambda 对象。

然而,目前 Clang 缺乏对 C++ lambda 的支持可能会给整个事情带来阻碍。

I recommend using the *_f versions of the libdispatch functions. All the block versions are implemented in terms of the function versions under the hood, and it's far easier to write a C++ template that produces a function that calls a lambda object than a template that produces a block that calls a lambda object.

However, the current lack of support in Clang for C++ lambdas may throw a damper on the whole thing.

挖个坑埋了你 2024-10-09 11:53:40

隐式启用此转换的补丁刚刚添加到 clang trunk 中。

A patch enabling this conversion implicitly was just added to clang trunk.

七禾 2024-10-09 11:53:40

一般来说,当 lambda 用于“向下”闭包时,可以通过 conversion:

[&](int i) { return i; }

to:

^(int i) { return i; }

将 c++ lambda 转换为 clang 块,但仍然存在一些细微的差异。 Clang 的块仅通过 const 捕获 C++ 类。我不知道这是否也包括 C++ POD 类型。

最后,如果需要“向上”闭合,那么两者就会出现巨大分歧。 Clang 的块需要捕获的变量用 __block 注释,编译器将在堆上分配它。而在 C++ 中,lambda 捕获的方式需要根据对象的生命周期来决定(即通过值进行复制或通过引用)。

同样在 C++ 中,复制闭包是由 C++ 中的复制构造函数机制自动处理的。然而,对于clang的块,需要调用Block_copyBlock_release来处理块的复制。可以用 C++ 编写一个简单的包装器来处理这个问题。例如:

typedef void (^simple_block)(void);
class block_wrapper 
{
  simple_block block;

public:
  block_wrapper (const simple_block& x)
  : block(Block_copy(x)) {}

  void operator() () const
  {
    block();
  }

  block_wrapper(const block_wrapper& rhs) 
  : block(Block_copy(rhs.block)) 
  {}

  block_wrapper& operator=(const block_wrapper& rhs)
  {
    if (this != &rhs)
    {
      Block_release(this->block);
      this->block = Block_copy(rhs.block);
    }
    return *this;
  }

  ~block_wrapper () 
  {
    Block_release(this->block);
  }
};

Generally, when lambda is used for "downward" closure, you can convert a c++ lambda to a clang block by converting:

[&](int i) { return i; }

to:

^(int i) { return i; }

There is still some subtle differences. Clang's blocks only capture C++ classes by const. I don't know if this includes C++ POD types too.

Finally, if "upward" closure is needed, then the two diverge drastically. Clang's blocks require variables captured to be annotated with __block, which the compiler will allocate it on the heap. Whereas, in C++, the way the lambda captures, needs to be decided based on the lifetime of the object.(That is by value making a copy or by reference).

Also in C++, copying the closure is handle automatically by the copy-constructor mechanism in C++. However, with clang's block, Block_copy and Block_release need to be called to handle the copying of the block. A simple wrapper can be written in C++ to handle this. For example:

typedef void (^simple_block)(void);
class block_wrapper 
{
  simple_block block;

public:
  block_wrapper (const simple_block& x)
  : block(Block_copy(x)) {}

  void operator() () const
  {
    block();
  }

  block_wrapper(const block_wrapper& rhs) 
  : block(Block_copy(rhs.block)) 
  {}

  block_wrapper& operator=(const block_wrapper& rhs)
  {
    if (this != &rhs)
    {
      Block_release(this->block);
      this->block = Block_copy(rhs.block);
    }
    return *this;
  }

  ~block_wrapper () 
  {
    Block_release(this->block);
  }
};
梦幻的味道 2024-10-09 11:53:40

我认为实际的转变是不可能的。与相反的情况不同,摆脱原来的 clang 块会产生一些无法恢复的副作用。虽然 C++0x lambda 可以通过引用捕获变量,但当您实际打算使用 lambda 时,没有执行任何特殊操作来确保原始变量仍然存在。另一方面,块可以与使用 __block 存储限定符声明的变量进行交互,在这种情况下,这些变量将保留在内存中(即使这意味着从堆栈复制到堆),只要该块存在(包括由 Block_copy 制作的副本):

__block 变量存在于词法范围之间共享的存储中
变量和所有块以及块
声明或创建的副本
变量的词法范围。因此,
存储将在破坏中幸存下来
堆栈帧(如果有任何副本)
框架内声明的块
生存到画面结束之后
(例如,通过排队
稍后执行的地方)。

因此,除非您打算保留原始块(从而包装而不是转换它),否则它的一些原始功能将丢失,因为 __block 变量将消失。

然而,我不是这方面的专家,很想听听其他意见:)

I don't think an actual convert is possible. Unlike the reverse case, getting rid of the original clang block, has some side effects that you can't recover from. While C++0x lambdas can capture variables by reference, nothing special is done to make sure the original variable is still there when you actually intend to use the lambda. Blocks on the other hand, can interact with variables declared with the __block storage qualifier, in which case these variables will be kept in memory (even if it means being copied from stack to heap) for as long as that block lives (including copies made by Block_copy):

__block variables live in storage that is shared between the lexical scope of
the variable and all blocks and block
copies declared or created within the
variable’s lexical scope. Thus, the
storage will survive the destruction
of the stack frame if any copies of
the blocks declared within the frame
survive beyond the end of the frame
(for example, by being enqueued
somewhere for later execution).

Therefore unless you intend to keep the original block around (and thus wrapping rather than converting it), some of its original functionality will be missing as the __block variables will be gone.

However, I'm no expert on the subjects and would love hearing other opinions :)

笔落惊风雨 2024-10-09 11:53:40

嗯,Clang 还不支持 lambda,Apple GCC 也不支持。 FSF GCC 最近足以支持 lambda 不支持块 AFAIK。所以它们之间的转换问题还不适用。

一旦 Clang 支持这两者,ObjC++ 模式中可能就有一种方法可以在它们之间进行转换。

Well, Clang doesn't yet support lambdas, and neither does the Apple GCC. FSF GCCs recent enough to support lambdas don't support blocks AFAIK. So the question of conversion between them doesn't yet apply.

Once Clang supports both of these, there may be a way in ObjC++ mode to convert between them.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文