我想知道是否可以将 C++0x lambda 转换为 clang 块。到目前为止,我在上面看到的任何内容都涉及到他们之间的差异之间的讨论。libdispatch
我研究这个的主要原因是为dispatch_*_f
.
到目前为止,我已经能够找到有关将 C++ lambda 转换为函数指针的信息,但这更多的是在相反的领域。
如果有人知道与此相关的任何事情,并且可以提供链接,或者至少为我指出正确的方向,我将不胜感激。(即使是“目前不可能”的答案也足够了)
我想知道是否可以将 C++0x lambda 转换为 clang 块。到目前为止,我在上面看到的任何内容都涉及到他们之间的差异之间的讨论。libdispatch
我研究这个的主要原因是为dispatch_*_f
.
到目前为止,我已经能够找到有关将 C++ lambda 转换为函数指针的信息,但这更多的是在相反的领域。
如果有人知道与此相关的任何事情,并且可以提供链接,或者至少为我指出正确的方向,我将不胜感激。(即使是“目前不可能”的答案也足够了)
A patch enabling this conversion implicitly was just added to clang trunk.
通常,当 lambda 用于“向下”闭包时,您可以通过以下转换将 c++ lambda 转换为 clang 块:
[&](int i) { return i; }
到:
^(int i) { return i; }
还是有一些细微的差别。Clang 的块仅通过 const 捕获 C++ 类。我不知道这是否也包括 C++ POD 类型。
最后,如果需要“向上”闭合,那么两者就会大相径庭。Clang 的块需要使用 注释捕获的变量__block
,编译器将在堆上分配它。而在 C++ 中,lambda 捕获的方式需要根据对象的生命周期来决定。(即通过值进行复制或通过引用)。
同样在 C++ 中,复制闭包是由 C++ 中的复制构造函数机制自动处理的。但是,用clang的block,Block_copy
需要Block_release
调用来处理block的拷贝。可以用 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);
}
};
我不认为真正的转换是可能的。与相反的情况不同,摆脱原来的 clang 块有一些你无法恢复的副作用。虽然 C++0x lambda 可以通过引用捕获变量,但当您实际打算使用 lambda 时,没有做任何特别的事情来确保原始变量仍然存在。另一方面,块可以与使用__block
存储限定符声明的变量交互,在这种情况下,这些变量将保存在内存中(即使这意味着从堆栈复制到堆)只要该块存在(包括由Block_copy
):
__block 变量存在于变量的词法范围和在变量的词法范围内声明或创建的所有块和块副本之间共享的存储中。因此,如果在帧内声明的块的任何副本在帧结束后仍然存在(例如,通过在某处排队以供以后执行),则存储将在堆栈帧的破坏中幸存下来。
因此,除非您打算保留原始块(并因此包装而不是转换它),否则它的一些原始功能将丢失,因为__block
变量将消失。
但是,我不是这方面的专家,我很想听听其他意见:)
好吧,Clang 还不支持 lambda,Apple GCC 也不支持。FSF GCCs 最近足以支持 lambdas 不支持块 AFAIK。所以它们之间的转换问题还不适用。
一旦 Clang 支持这两者,可能有一种方法可以在 ObjC++ 模式下在它们之间进行转换。
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.