2009-08-15

lambdaのちょっと分からない点

以下の場合を考える。

class Foo
{

int x ;

public :

void f()
{
  // f()の中で百個の自動変数を使う。
  int val001, val002, val003, /*...*/ val100 ;

  // lambda expression
  [&]{// #1
    // ここで、valXXXなる一連の変数を全部使いたい。

     // さらにlambda expression
    [&]
    {// #2
     // ここで、#1の直前のメンバ関数であるf()のthisを使いたい。
     // と同時に、valXXXなる一連の変数も使いたい。
      this->x = val001 ;
    }() ;
  }() ;
}

} ;

上記のコードは、おそらく失敗するであろうと思われる。というのも、lambdaは直前の自動変数しかキャプチャできないからだ。#1のキャプチャリストに、明示的に書いたとしても、#2で使うことは出来ない。なぜならば、キャプチャした変数は、lambdaのクロージャオブジェクトのメンバ変数という扱いだからだ。従って、上記コードの正しい例はこうなる、と思う。

class Foo
{

int x ;

public :

void f()
{
  // f()の中で百個の自動変数を使う。
  int val001 = 1, val002 = 2, val003 = 3, /*...*/ val100 = 100 ;

  // lambda expression
  [&]{// #1
     auto auto_val001 = val001 ;
     // 使う必要のあるvalXXXを、ここで全部明示的に自動変数に代入。

     // さらにlambda expression
    [&]
    {// #2
      this->x = auto_val001 ;
    }() ;
  }() ;
}

} ;

たとえ、#2でthisをキャプチャしても、それは#1のlambdaのクロージャオブジェクトのthisにはならない。#1の直前のメンバ関数のthisになる。したがって、this->val001などとやって、#2から#1のキャプチャした変数を全部使うなどと言う抜け道はない。もし本当に使いたいのであれば、#1のcompound-statement内で、地道に必要な変数を全部、自動変数に代入してやる必要がある。

どうも、lambdaのネストは使いづらいな。

追記:#2のthisは#1のキャプチャしたthisであり、つまり#1を直接包括するメンバ関数のthisなので、thisを自動変数にする必要はない。

No comments: