blogの更新がとんとご無沙汰してます。すんませんねー
なんかもー、本業でわたわたしてまして、おうち帰るとメシ食ってばたんきゅ、な日が続いてますのん。
わんくま東京勉強会も顔ださなくなっちゃいました。もーちょいで楽になるハズなんですけども。
先日MVP Open Dayにお邪魔しました。百名を超えるMVPのみなさんが顔を合わせ、新人MVPをいぢくり回す会ですわ(ホホホ
久しぶりにMVPのみなさんと顔をあわせ、ちょっとだけ元気をもらえたように思います。ありがとでした。
ちょっとだけ元気もらった勢いでVC++10のlambdaのカラクリを推測するココロミなど。
#include <iostream>
#include <typeinfo>
int main() {
  int n;
  auto lambda = [=](void* p) { 
    std::cout << p << '\t' << (void*)&n << std::endl; 
  };
  int m;
  lambda(&n);
  lambda(&lambda);
  lambda(&m);
  std::cout << typeid(lambda).name() << std::endl;
}
こいつをコンパイル/実行すると
0028FDFC        0028FE00
0028FE00        0028FE00
0028FDF8        0028FE00
class `anonymous namespace'::<lambda0>
興味深い結果が得られました。どうやらメモリ上には:
0028FDF8: m
0028FDFC: n
0028FE00: lambda と lambda内のn
なんてなレイアウトでローカル変数が作られた様子。
n と lambda内のn とが異なる位置にあります。この二つは別物として扱われてるてことね。
値キャプチャされたnはlambda内で書き換えられないからくりがココにあるみたい。
また、lambdaとlambda内のnとが同じ位置にあること、lambdaの型がclassであることからしてlambda内のnはclassの最初のメンバとなってるポ。
してみるとコンパイラ君、おそらくはこんなコードを内部的に生成するのでしょう:
namespace {
  class lambda0 {
    int n_; // 値キャプチャしたn
  public:
    lambda0(int captured_var) : n_(captured_var) {}
    void operator()(void* p) {
      std::cout << p << '\t' << (void*)&n_ << std::endl; 
    }
  }
}
int main() {
  int m;
  int n;
  lambda0 lambda(n);
  lambda(&n);
  lambda(&lambda);
  lambda(&m);
  std::cout << typeid(lambda).name() << std::endl;
}
lambda式を定義するたんびにnanonymousな名前空間にコソーリclassを生成するのであれば、
C++/CLIでmanagedな変数をキャプチャできないことが説明つくです。class内にはmanagedは置けないもんね。