25

C++0x ラムダを clang ブロックに変換できるかどうか疑問に思いました。これまでのところ、私が見たものには、それらの違いの間の議論が含まれていました. これを調べる主な理由は、 の最終的なラッパーを作成することです。関数libdispatchについてはよく知っdispatch_*_fていますが、ブロックの対応物と比較して、それらの使用に関する情報はまったく不足していました。

これまでのところ、C++ ラムダを関数ポインターに変換する方法に関する情報を見つけることができましたが、これは逆の領域にあります。

誰かがこれに関連することを知っていて、リンクを提供してくれるか、少なくとも正しい方向に向けてくれるなら、本当に感謝しています. (「これは現在不可能です」という回答でも十分です)

4

5 に答える 5

12

この変換を暗黙的に有効にするパッチが、clang トランクに追加されました。

于 2012-02-15T22:21:07.853 に答える
6

一般に、ラムダが「下方」クロージャーに使用される場合、次のように変換することで、c++ ラムダを clang ブロックに変換できます。

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

に:

^(int i) { return i; }

まだいくつかの微妙な違いがあります。Clang のブロックは、const によって C++ クラスのみをキャプチャします。これに C++ POD タイプも含まれているかどうかはわかりません。

最後に、「上向き」の閉鎖が必要な場合、この 2 つは大幅に異なります。Clang のブロックでは、キャプチャされた変数に で注釈を付ける必要が__blockあり、コンパイラはそれをヒープに割り当てます。一方、C++ では、ラムダがキャプチャする方法は、オブジェクトの有効期間に基づいて決定する必要があります (つまり、コピーを作成する値または参照によって)。

また、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);
  }
};
于 2012-02-12T07:09:45.437 に答える
2

実際の変換は不可能だと思います。逆のケースとは異なり、元の clang ブロックを取り除くと、回復できない副作用がいくつかあります。C++0x ラムダは参照によって変数をキャプチャできますが、実際にラムダを使用する場合、元の変数がまだそこにあることを確認するために特別なことは何も行われません。一方、ブロックは、__blockストレージ修飾子で宣言された変数と対話できます。その場合、これらの変数は、そのブロックが存続する限り (スタックからヒープにコピーされることを意味する場合でも) メモリに保持されます (によって作成されたコピーを含む)。Block_copy):

__block 変数は、変数のレキシカル スコープと、変数のレキシカル スコープ内で宣言または作成されたすべてのブロックおよびブロック コピーとの間で共有されるストレージに存在します。したがって、フレーム内で宣言されたブロックのコピーがフレームの最後を超えて存続する場合 (たとえば、後で実行するためにどこかでキューに入れられることによって)、ストレージはスタック フレームが破棄されても存続します。

したがって、元のブロックを保持する (つまり、変換するのではなくラップする) つもりでない限り、__block変数がなくなるため、元の機能の一部が失われます。

ただし、私はこのテーマの専門家ではないので、他の意見を聞きたいです:)

于 2010-11-10T21:36:21.157 に答える
0

ええと、Clangはまだラムダをサポートしていませんし、AppleGCCもサポートしていません。ラムダをサポートするのに十分最近のFSFGCCは、ブロックAFAIKをサポートしていません。したがって、それらの間の変換の問題はまだ適用されません。

Clangがこれらの両方をサポートすると、ObjC++モードでそれらの間で変換する方法があるかもしれません。

于 2010-12-14T15:58:45.880 に答える
0

*_flibdispatch 関数のバージョンを使用することをお勧めします。すべてのブロック バージョンは内部の関数バージョンに関して実装されており、ラムダ オブジェクトを呼び出すブロックを生成するテンプレートよりも、ラムダ オブジェクトを呼び出す関数を生成する C++ テンプレートを作成する方がはるかに簡単です。

ただし、現在、Clang で C++ ラムダがサポートされていないため、全体が台無しになる可能性があります。

于 2012-02-12T08:24:10.763 に答える