C++: lambda の参照キャプチャは const 性を損なわない? このエントリーをはてなブックマークに追加

C++ の勉強ということでちょいちょいスモールケースを書いては意味もなく github に commit するということをやっているのですが…

んー、何でしょうねこの雑なコード(^_^;A これ自体は確か、ステータスの変化を検知してステータスの種類にかかわらず共通の処理を自動で走らせるようにしたいんだけど、そうするとあれとこれとそれを変更しようとした時にあれを変更した時にもこれを変更した時にもそれを変更した時にも処理が重複して走っちゃうから無駄だよねってケースを想定して、じゃあ今あるステータスを全部一時的な構造体に突っ込んだものを引数にとってその構造体に変更を加えて返すコールバックを引数に取るようにすればいいんじゃね? って思ったんだけど、そんなの lambda で書きたいに決まってるけど変数キャプチャ付きの lambda は関数ポインタに変換できないじゃんねっていう訳で、コールバックに関数ポインタじゃなくて lambda を受け取る template メソッドにしてしまえ、ということを試してみたくて書いていたものでした (今考えたらそも素直に std::function 使えよ…って話ですねorz)。

で、その試み自体は割とどうでもよくて、そういえば lambda の変数キャプチャで指定できるのはコピーか参照かのどっちかだけだけど、元々のキャプチャされる変数が const だった場合に、参照キャプチャしちゃった先の lambda の中で const 性が失われる (つまり、値の書き換えができちゃう) なんてことはないのかなぁ、というのがちょっと気になりました。

struct A {
    void func(minimum::Data &data, std::string const& birth, std::string const& company)
    {
        data.modify([&birth, &company](minimum::Data::Detail detail){
            detail.keys.erase(detail.keys.begin() + 1);
            auto role = detail.values[1];
            detail.values.erase(detail.values.begin() + 1);
            detail.keys.push_back("birth");
            // birth = "書き換えちゃった^-^";    //エラー
            detail.values.push_back(birth);
            detail.keys.push_back("company");
            detail.values.push_back(company);
            return detail;
        });
    }
};

上記コードで birthstd::string const& 型の引数として宣言されており、それを lambda で参照キャプチャし lambda 内で変更しようとすると、コンパイルエラーになる、ということが手元の GCC 4.8.2 では確認されました (-std=c++11)。

…いや、ここで N3337 でも参照して規格のこの部分の記述からしてそうなるのが正しいようですとか言い切れればカッコイイんですけど、少なくとも lambda について説明のあった 5.1.2節からはそんな記述を読み取ることはおいらには出来まへんでした… orz 。このへんもうちょっと読み慣れることができればいいんですけどね…。


2014/7/25 21:46 – 追記

std::function を使って改良してみました。うわー、こっちのほうが全然スマートじゃないですかヤダー

2014 年 7 月 25 日 by 村山 俊之

タグ: ,

コメントをどうぞ