cocos2d-x3.Xでlambdaする

# cocos2d-x3.Xでlambdaする

## お決まりのやつ
こんにちは、[Cocos2d-x Advent Calendar](http://qiita.com/advent-calendar/2014/cocos2d-x)及び、[CYBIRDエンジニア Advent Calendar](http://qiita.com/advent-calendar/2014/cybird)14日目の[@ikemonn](http://qiita.com/ikemonn)です。


昨日は、Cocos2d-xの方は[@mettoboshi](http://qiita.com/mettoboshi)さんの[AppWarpとCubismSDKを使って応援アプリっぽいものを作ってみた](http://qiita.com/mettoboshi/items/1467eea2f4c870e31df8)でした。AppWarpを使うとサーバ側のコーディングをせずにリアルタイムゲームを作れるの良いですね！

CYBIRDの方は、[@Satoshi_Nakamura](http://qiita.com/Satoshi_Nakamura)さんの[TCOとちょっとだけIDCFクラウド](http://qiita.com/Satoshi_Nakamura/items/e9e0e2d8d79e20d6d817)でした。
> プライベートクラウドの場合はあまり気にしなくても良いかもしれませんが、パブリッククラウドの場合（時間単位の従量課金）、1時間分でも安くしたいものです。
> 単純計算でこう見ると、
>1週間 フルタイム(24H)      ・・・ 168時間
>1週間 平日10:00~22:00稼働  ・・・  60時間

上記で比較されているように従量課金のサーバを使ってる時は、cronを設定して停止・起動するの試してみようと思います！


## 本日の要約
- ラムダ式は無名関数のようなもの
- ラムダ式便利だからみんな使おう！
    - わざわざ.hファイルに関数宣言書くまでもないような、ちょっとした関数を書く時
- こんな感じでラムダ式を書く→```[キャプチャ](引数){式}```

## 自己紹介
入社3年目で現在はCocos2d-x 3.2を使ってアプリの開発をしています。
2~3ヶ月前からネイティブ側の開発をさせてもらっていて、それまではPHPを書いていました。

## ラムダ式の概要
Cocos2d-xの3.0からラムダ式が使えるようになりました。
JSの無名関数をイメージしてもらうと分かりやすいと思います。
わざわざ.hファイルに関数宣言書くまでもないような、ちょっとした関数を書く時に便利なので是非使い方を覚えてみてください！
## 文法
文法は下記のようになっています。

```
[キャプチャ](引数)
{
    式
}
```

- [] : キャプチャリスト
    - ラムダ式の中でアクセスする変数を記述する。
- () : ラムダ式の引数
- {} : ラムダ式本体

ラムダ式は()内の引数を取り、{}の処理を実行します。
キャプチャリストについては後述します。

例えば足し算だと下記のように書けます。

```cpp
auto add = [](int x, int y)
{
    return x + y;
};

add(1, 2);  // 1 + 2 = 3
```

ぱっと見ると\[\]\(\)\{\}のように記号ばかりで、難しそうですが意味が分かれば簡単ですね！

## キャプチャリスト
さて、先ほどおいておいた、キャプチャリストについて説明します。
ラムダ式内では、グローバル関数やstatic変数、定数等は使えますが、ローカル変数や関数の引数はそのままでは使えません。

```cpp
int x = 1;              // ローカル変数
auto add = [](int y)
{  
    return x + y;       // キャプチャに何も指定していないとxにアクセスできずエラー
};
```



そこでローカル変数をラムダ式内で使用できるようにする**キャプチャ**という機能があります。

キャプチャには下記の2種類があります。

- 参照キャプチャ
    - 変数の**参照**が渡される
- コピーキャプチャ
    - 変数の**値がコピーされて**渡される

参照キャプチャやコピーキャプチャを使うことで、ラムダ式外の変数をラムダ式で使うことができるようになります。

### 参照キャプチャ
参照キャプチャを使うと、ラムダ式内で変数の参照を保持します。
つまり、ラムダ式内で変数を書き換えると、**ラムダ式外の変数も書き換わります**。
キャプチャリストには**[&]**と記述します。

```cpp
int x = 1;
auto add = [&](int y)      // ローカル変数へのアクセスを可能にする
{    
    x++;                   // ラムダ式外のxの値も2になる
    return x + y;
};
log("x = %d", x);          // x = 2
log("add = %d", add(1));   // 2 + 1 = 3
```

### コピーキャプチャ
コピーキャプチャを使うと、ローカル変数をコピーした値をラムダ式内に保持します。
ラムダ式の関数呼び出し演算子はconstになっているので、**ラムダ式内で変数を書き換えようとするとエラー**になります。
キャプチャリストには、使いたい**変数名をカンマ区切り**で記述するか、**[=]**と書くことで変数名のリストを省略することが出来ます。

```cpp
// 変数をカンマ区切りで書く場合
int x = 1;
int y = 2;
auto test = [x, y](int z)      // ローカル変数x, yの値をコピーする
{    
    // x++;                    // このようにxを書き換えようとするとエラー
    return x + y + z;          // x = 1, y = 2が渡されている
};
log("test = %d", test(3));   // 1 + 2 + 3 = 6
```

```cpp
// [=]と書く場合
int x = 1;
int y = 2;
auto test = [=](int z)       // ローカル変数x, yの値をコピーする
{     
    return x + y + z;       
};
log("test = %d", test(3));   // 1 + 2 + 3 = 6
```

どうしてもコピーキャプチャで変数を書き換えたい場合はmutableを使って書き換えることが出来ます。
mutableは、()の後、{}の前に記述します。

```cpp
int x = 1;
int y = 2;
auto test = [x, y](int z)mutable         // ローカル変数x, yの値をコピーする
{       
    x++;                                 // mutableがあるので、コピーされたxの値は2になる
    return x + y + z;          
};
log("test = %d", test(3));   // 2 + 2 + 3 = 7
log("x = %d", x);            // x = 1 コピーなのでラムダ式外のxは書きかわらない
```


## 具体例
例えば、Spriteを生成、位置の設定、大きさの変更を行うラムダ式は下記のように書けます。

```cpp
bool HelloWorld::init()
{
    if ( !Layer::init() )
    {
        return false;
    }
    
    Point point = Point(550, 300);
    float scale = 1.5;
    auto createImg = [point, scale, this](const std::string& name)
    {
        Sprite* img = Sprite::create(name);
        img->setPosition(point);
        img->setScale(scale);
        this->addChild(img);
    };
    
    createImg("HelloWorld.png");    
    
    return true;
}
```

![lambdaTest.png](https://qiita-image-store.s3.amazonaws.com/0/18573/6919fafa-4540-a19a-7879-a0f5b7006af3.png)


## まとめ

- ラムダ式は無名関数のようなもの
- ラムダ式便利だからみんな使おう！
    - わざわざ.hファイルに関数宣言書くまでもないような、ちょっとした関数を書く時
- こんな感じでラムダ式を書く→```[キャプチャ](引数){式}```

## 最後に

[Cocos2d-x Advent Calendar](http://qiita.com/advent-calendar/2014/cocos2d-x)の明日は[@bitlate_chocola](http://qiita.com/bitlate_chocola)さんです！

[CYBIRDエンジニア Advent Calendar 2014](http://qiita.com/advent-calendar/2014/cybird)の明日は、[@megadreams14](http://qiita.com/megadreams14)さんです！
同期の中でも最強エンジニアと名高い[@megadreams14](http://qiita.com/megadreams14)の記事楽しみですね！

      

## 参考
[ラムダ式 ‐ 通信用語の基礎知識](http://www.wdic.org/w/TECH/%E3%83%A9%E3%83%A0%E3%83%80%E5%BC%8F)
[C++14 のラムダ式 完全解説 前編 - 野良C++erの雑記帳](http://d.hatena.ne.jp/gintenlabo/20130516/1368711542)
[C++14 のラムダ式 完全解説 中編 - 野良C++erの雑記帳](http://d.hatena.ne.jp/gintenlabo/20130526/1369565989)
[本の虫: C++11参考書の公開：C++11の文法と機能](http://cpplover.blogspot.jp/2009/11/lambda.html)